<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"

#include <Poco/Logger.h>
#include <Poco/LoggingFactory.h>
#include <Poco/FormattingChannel.h>
#include <Poco/SplitterChannel.h>
#include <Poco/LocalDateTime.h>
#include "Poco/UnicodeConverter.h"

#include "Foundation.h"
/*
#include <direct.h>
#include <Windows.h>
*/
namespace Foundation
{
    const char *Framework::DEFAULT_EVENT_SUBSCRIBER_TREE_PATH = "./data/event_tree.xml";

    Framework::Framework() : exit_signal_(false)
    {
        application_ = ApplicationPtr(new Application(this));
        platform_ = PlatformPtr(new Platform(this));
		// Create config manager
		config_manager_ = ConfigurationManagerPtr(new ConfigurationManager(this));

        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("version_major"), std::string("0"));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("version_minor"), std::string("1"));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("application_name"), std::string("realXtend"));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("log_console"), bool(true));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("log_level"), std::string("information"));

        platform_->PrepareApplicationDataDirectory(); // depends on config

        CreateLoggingSystem(); // depends on config and platform

        // create managers
        module_manager_ = ModuleManagerPtr(new ModuleManager(this));
        component_manager_ = ComponentManagerPtr(new ComponentManager(this));
        service_manager_ = ServiceManagerPtr(new ServiceManager(this));
        event_manager_ = EventManagerPtr(new EventManager(this));
    }

    Framework::~Framework()
    {
        Poco::Logger::shutdown();

        for (size_t i=0 ; i<log_channels_.size() ; ++i)
            log_channels_[i]->release();

        log_channels_.clear();
        log_formatter_->release();
    }

    void Framework::CreateLoggingSystem()
    {
        Poco::LoggingFactory *loggingfactory = new Poco::LoggingFactory();

        Poco::Channel *consolechannel = NULL;
        if (config_manager_->GetSetting<bool>(Framework::ConfigurationGroup(), "log_console"))
            consolechannel = loggingfactory->createChannel("ConsoleChannel");

        Poco::Channel *filechannel = loggingfactory->createChannel("FileChannel");

        std::wstring logfilepath_w = platform_->GetUserDocumentsDirectoryW();
        logfilepath_w += L"/" + Core::ToWString(config_manager_->GetSetting<std::string>(Framework::ConfigurationGroup(), "application_name")) + L".log";
        std::string logfilepath;
        Poco::UnicodeConverter::toUTF8(logfilepath_w, logfilepath);

        filechannel->setProperty("path",logfilepath);
        filechannel->setProperty("rotation","3M");
        filechannel->setProperty("archive","number");
        filechannel->setProperty("compress","false");

        Poco::SplitterChannel *splitterchannel = new Poco::SplitterChannel();
        if (consolechannel)
            splitterchannel->addChannel(consolechannel);
        splitterchannel->addChannel(filechannel);

        log_formatter_ = loggingfactory->createFormatter("PatternFormatter");
        log_formatter_->setProperty("pattern","%H:%M:%S [%s] %t");
        log_formatter_->setProperty("times","local");
        Poco::Channel *formatchannel = new Poco::FormattingChannel(log_formatter_,splitterchannel);

        try
        {
            Poco::Logger::create("",formatchannel,Poco::Message::PRIO_TRACE);
            Poco::Logger::create("Foundation",Poco::Logger::root().getChannel() ,Poco::Message::PRIO_TRACE);
        } catch (Poco::ExistsException)
        {
            assert (false && "Somewhere, a message is pushed to log before the logger is initialized.");
        }

        Poco::LocalDateTime *currenttime = new Poco::LocalDateTime();
        std::string timestring = boost::lexical_cast<std::string>(currenttime->day()) + "/";
        timestring.append(boost::lexical_cast<std::string>(currenttime->month()) + "/");
        timestring.append(boost::lexical_cast<std::string>(currenttime->year()) + " ");
        timestring.append(boost::lexical_cast<std::string>(currenttime->hour()) + ":");
        timestring.append(boost::lexical_cast<std::string>(currenttime->minute()) + ":");
        timestring.append(boost::lexical_cast<std::string>(currenttime->second()));

        try
        {
            Foundation::RootLogInfo("Log file opened on " + timestring);
        } catch(Poco::OpenFileException)
        {
            // Do not create the log file.
            splitterchannel->removeChannel(filechannel);
            Foundation::RootLogInfo("Poco::OpenFileException. Log file not created.");
        }

#ifndef _DEBUG
        // make it so debug messages are not logged in release mode
        std::string log_level = config_.GetSettingFromFile<std::string>(Framework::ConfigurationGroup(), "log_level");
        Poco::Logger::get("Foundation").setLevel(log_level);
#endif

        if (consolechannel)
            log_channels_.push_back(consolechannel);
        log_channels_.push_back(filechannel);
        log_channels_.push_back(splitterchannel);
        log_channels_.push_back(formatchannel);

        delete currenttime;
        delete loggingfactory;
    }

    void Framework::Go()
    {
/*
#ifdef WIN32
        wchar_t buffer[_MAX_PATH*2];
        if (_wgetcwd( buffer, _MAX_PATH ) != NULL)
        {
            wcscat(buffer, L"/modules/core");
            SetDllDirectory(buffer);
        }
#endif
*/
        LoadModules();

        // commands must be registered after modules are loaded and initialized
        RegisterConsoleCommands();

        // add event subscribers now, that all modules are loaded/initialized
        event_manager_->LoadEventSubscriberTree(DEFAULT_EVENT_SUBSCRIBER_TREE_PATH);

        boost::timer timer;

        // main loop
        while (exit_signal_ == false)
        {
            double frametime = timer.elapsed();
            timer.restart();
            // do synchronized update for modules
            module_manager_->UpdateModules(frametime);

            // call asynchronous update on modules / do parallel tasks

            // synchronize shared data across modules
            //mChangeManager->_propagateChanges();

            // if we have a renderer service, render now

            if (service_manager_->IsRegistered(Service::ST_Renderer))
            {
                Foundation::RenderServiceInterface *renderer =
                    service_manager_->GetService<RenderServiceInterface>(Service::ST_Renderer);
                renderer->Render();
            }

        }

         UnloadModules();
    }

    void Framework::LoadModules()
    {
        module_manager_->LoadAvailableModules();
        module_manager_->InitializeModules();
    }

    void Framework::UnloadModules()
    {
        module_manager_->UninitializeModules();
        module_manager_->UnloadModules();
    }

    Console::CommandResult Framework::ConsoleLoadModule(const Core::StringVector &params)
    {
        if (params.size() != 2 && params.size() != 1)
            return Console::ResultInvalidParameters();

        std::string lib = params[0];
        std::string entry = params[0];
        if (params.size() == 2)
            entry = params[1];

        bool result = module_manager_->LoadModuleByName(lib, entry);
        event_manager_->ValidateEventSubscriberTree();

        if (!result)
            return Console::ResultFailure("Library or module not found.");

        return Console::ResultSuccess("Module " + entry + " loaded.");
    }

    Console::CommandResult Framework::ConsoleUnloadModule(const Core::StringVector &params)
    {
        if (params.size() != 1)
            return Console::ResultInvalidParameters();

        bool result = false;
        if (module_manager_->HasModule(params[0]))
        {
            result = module_manager_->UnloadModuleByName(params[0]);
            event_manager_->ValidateEventSubscriberTree();
        }

        if (!result)
            return Console::ResultFailure("Module not found.");

        return Console::ResultSuccess("Module " + params[0] + " unloaded.");
    }

    void Framework::RegisterConsoleCommands()
    {
        Console::CommandService *console = GetService<Console::CommandService>(Foundation::Service::ST_ConsoleCommand);
        console->RegisterCommand(Console::CreateCommand("LoadModule",
            "Loads a module from shared library. Usage: LoadModule(lib, entry)",
            Console::Bind(this, &Framework::ConsoleLoadModule)));

        console->RegisterCommand(Console::CreateCommand("UnloadModule",
            "Unloads a module. Usage: UnloadModule(name)",
            Console::Bind(this, &Framework::ConsoleUnloadModule)));
    }
}

<commit_msg>Fixed release mode log level setting.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"

#include <Poco/Logger.h>
#include <Poco/LoggingFactory.h>
#include <Poco/FormattingChannel.h>
#include <Poco/SplitterChannel.h>
#include <Poco/LocalDateTime.h>
#include "Poco/UnicodeConverter.h"

#include "Foundation.h"
/*
#include <direct.h>
#include <Windows.h>
*/
namespace Foundation
{
    const char *Framework::DEFAULT_EVENT_SUBSCRIBER_TREE_PATH = "./data/event_tree.xml";

    Framework::Framework() : exit_signal_(false)
    {
        application_ = ApplicationPtr(new Application(this));
        platform_ = PlatformPtr(new Platform(this));
		// Create config manager
		config_manager_ = ConfigurationManagerPtr(new ConfigurationManager(this));

        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("version_major"), std::string("0"));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("version_minor"), std::string("1"));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("application_name"), std::string("realXtend"));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("log_console"), bool(true));
        config_manager_->DeclareSetting(Framework::ConfigurationGroup(), std::string("log_level"), std::string("information"));

        platform_->PrepareApplicationDataDirectory(); // depends on config

        CreateLoggingSystem(); // depends on config and platform

        // create managers
        module_manager_ = ModuleManagerPtr(new ModuleManager(this));
        component_manager_ = ComponentManagerPtr(new ComponentManager(this));
        service_manager_ = ServiceManagerPtr(new ServiceManager(this));
        event_manager_ = EventManagerPtr(new EventManager(this));
    }

    Framework::~Framework()
    {
        Poco::Logger::shutdown();

        for (size_t i=0 ; i<log_channels_.size() ; ++i)
            log_channels_[i]->release();

        log_channels_.clear();
        log_formatter_->release();
    }

    void Framework::CreateLoggingSystem()
    {
        Poco::LoggingFactory *loggingfactory = new Poco::LoggingFactory();

        Poco::Channel *consolechannel = NULL;
        if (config_manager_->GetSetting<bool>(Framework::ConfigurationGroup(), "log_console"))
            consolechannel = loggingfactory->createChannel("ConsoleChannel");

        Poco::Channel *filechannel = loggingfactory->createChannel("FileChannel");

        std::wstring logfilepath_w = platform_->GetUserDocumentsDirectoryW();
        logfilepath_w += L"/" + Core::ToWString(config_manager_->GetSetting<std::string>(Framework::ConfigurationGroup(), "application_name")) + L".log";
        std::string logfilepath;
        Poco::UnicodeConverter::toUTF8(logfilepath_w, logfilepath);

        filechannel->setProperty("path",logfilepath);
        filechannel->setProperty("rotation","3M");
        filechannel->setProperty("archive","number");
        filechannel->setProperty("compress","false");

        Poco::SplitterChannel *splitterchannel = new Poco::SplitterChannel();
        if (consolechannel)
            splitterchannel->addChannel(consolechannel);
        splitterchannel->addChannel(filechannel);

        log_formatter_ = loggingfactory->createFormatter("PatternFormatter");
        log_formatter_->setProperty("pattern","%H:%M:%S [%s] %t");
        log_formatter_->setProperty("times","local");
        Poco::Channel *formatchannel = new Poco::FormattingChannel(log_formatter_,splitterchannel);

        try
        {
            Poco::Logger::create("",formatchannel,Poco::Message::PRIO_TRACE);
            Poco::Logger::create("Foundation",Poco::Logger::root().getChannel() ,Poco::Message::PRIO_TRACE);
        } catch (Poco::ExistsException)
        {
            assert (false && "Somewhere, a message is pushed to log before the logger is initialized.");
        }

        Poco::LocalDateTime *currenttime = new Poco::LocalDateTime();
        std::string timestring = boost::lexical_cast<std::string>(currenttime->day()) + "/";
        timestring.append(boost::lexical_cast<std::string>(currenttime->month()) + "/");
        timestring.append(boost::lexical_cast<std::string>(currenttime->year()) + " ");
        timestring.append(boost::lexical_cast<std::string>(currenttime->hour()) + ":");
        timestring.append(boost::lexical_cast<std::string>(currenttime->minute()) + ":");
        timestring.append(boost::lexical_cast<std::string>(currenttime->second()));

        try
        {
            Foundation::RootLogInfo("Log file opened on " + timestring);
        } catch(Poco::OpenFileException)
        {
            // Do not create the log file.
            splitterchannel->removeChannel(filechannel);
            Foundation::RootLogInfo("Poco::OpenFileException. Log file not created.");
        }

#ifndef _DEBUG
        // make it so debug messages are not logged in release mode
        std::string log_level = config_manager_->GetSetting<std::string>(Framework::ConfigurationGroup(), "log_level");
        Poco::Logger::get("Foundation").setLevel(log_level);
#endif

        if (consolechannel)
            log_channels_.push_back(consolechannel);
        log_channels_.push_back(filechannel);
        log_channels_.push_back(splitterchannel);
        log_channels_.push_back(formatchannel);

        delete currenttime;
        delete loggingfactory;
    }

    void Framework::Go()
    {
/*
#ifdef WIN32
        wchar_t buffer[_MAX_PATH*2];
        if (_wgetcwd( buffer, _MAX_PATH ) != NULL)
        {
            wcscat(buffer, L"/modules/core");
            SetDllDirectory(buffer);
        }
#endif
*/
        LoadModules();

        // commands must be registered after modules are loaded and initialized
        RegisterConsoleCommands();

        // add event subscribers now, that all modules are loaded/initialized
        event_manager_->LoadEventSubscriberTree(DEFAULT_EVENT_SUBSCRIBER_TREE_PATH);

        boost::timer timer;

        // main loop
        while (exit_signal_ == false)
        {
            double frametime = timer.elapsed();
            timer.restart();
            // do synchronized update for modules
            module_manager_->UpdateModules(frametime);

            // call asynchronous update on modules / do parallel tasks

            // synchronize shared data across modules
            //mChangeManager->_propagateChanges();

            // if we have a renderer service, render now

            if (service_manager_->IsRegistered(Service::ST_Renderer))
            {
                Foundation::RenderServiceInterface *renderer =
                    service_manager_->GetService<RenderServiceInterface>(Service::ST_Renderer);
                renderer->Render();
            }

        }

         UnloadModules();
    }

    void Framework::LoadModules()
    {
        module_manager_->LoadAvailableModules();
        module_manager_->InitializeModules();
    }

    void Framework::UnloadModules()
    {
        module_manager_->UninitializeModules();
        module_manager_->UnloadModules();
    }

    Console::CommandResult Framework::ConsoleLoadModule(const Core::StringVector &params)
    {
        if (params.size() != 2 && params.size() != 1)
            return Console::ResultInvalidParameters();

        std::string lib = params[0];
        std::string entry = params[0];
        if (params.size() == 2)
            entry = params[1];

        bool result = module_manager_->LoadModuleByName(lib, entry);
        event_manager_->ValidateEventSubscriberTree();

        if (!result)
            return Console::ResultFailure("Library or module not found.");

        return Console::ResultSuccess("Module " + entry + " loaded.");
    }

    Console::CommandResult Framework::ConsoleUnloadModule(const Core::StringVector &params)
    {
        if (params.size() != 1)
            return Console::ResultInvalidParameters();

        bool result = false;
        if (module_manager_->HasModule(params[0]))
        {
            result = module_manager_->UnloadModuleByName(params[0]);
            event_manager_->ValidateEventSubscriberTree();
        }

        if (!result)
            return Console::ResultFailure("Module not found.");

        return Console::ResultSuccess("Module " + params[0] + " unloaded.");
    }

    void Framework::RegisterConsoleCommands()
    {
        Console::CommandService *console = GetService<Console::CommandService>(Foundation::Service::ST_ConsoleCommand);
        console->RegisterCommand(Console::CreateCommand("LoadModule",
            "Loads a module from shared library. Usage: LoadModule(lib, entry)",
            Console::Bind(this, &Framework::ConsoleLoadModule)));

        console->RegisterCommand(Console::CreateCommand("UnloadModule",
            "Unloads a module. Usage: UnloadModule(name)",
            Console::Bind(this, &Framework::ConsoleUnloadModule)));
    }
}

<|endoftext|>


<commit_before>#ifndef MULTIPLEXER_HH
#define MULTIPLEXER_HH

#include <fastarduino/devices/SIPO.hh>

enum class BlinkMode: uint8_t
{
	// In this mode, no blink occurs at all
	NO_BLINK = 0,
	// In this mode, blink is done for LEDs that are ON (in _data), whatever _blinks content
	BLINK_ALL_DATA,
	// In this mode, blink is done for LEDs that are set to blink (in _blinks), whatever if they're ON or not (in _data)
	BLINK_ALL_BLINKS,
	// In this mode, blink is done for LEDs that are ON (in _data) and set to blink (in _blinks)
	BLINK_BLINKABLE_DATA
};

// Special "traits" used by Multiplexer to determine, at compile time, its behavior based on the number of
// ROWS and COLUMNS
template<uint8_t ROWS_, uint8_t COLUMNS_>
struct MATRIX_TRAIT
{
	using COLUMN_TYPE = uint8_t;
	using ROW_TYPE = uint8_t;
	using TYPE = uint16_t;
	static TYPE as_type(COLUMN_TYPE column, ROW_TYPE row);
	static constexpr const bool SUPPORTED = false;
};

template<typename ROW_TYPE_, typename COLUMN_TYPE_, typename TYPE_>
struct MATRIX_TRAIT_IMPL
{
	using COLUMN_TYPE = COLUMN_TYPE_;
	using ROW_TYPE = ROW_TYPE_;
	using TYPE = TYPE_;
	static TYPE as_type(COLUMN_TYPE column, ROW_TYPE row)
	{
		return ((TYPE(column)) << (8 * sizeof(ROW_TYPE))) | TYPE(row);
	}
	static constexpr const bool SUPPORTED = true;
};

template<> struct MATRIX_TRAIT<8, 8>: MATRIX_TRAIT_IMPL<uint8_t, uint8_t, uint16_t> {};
template<> struct MATRIX_TRAIT<16, 16>: MATRIX_TRAIT_IMPL<uint16_t, uint16_t, uint32_t> {};
//TODO other template for more special cases: 16+8, 8+16, 24+8...

//TODO do we need BLINK_COUNT as class template argument, or just as method template argument?

template<	Board::DigitalPin CLOCK,
			Board::DigitalPin LATCH,
			Board::DigitalPin DATA,
			uint16_t BLINK_COUNT = 16,
			uint8_t ROWS_ = 8,
			uint8_t COLUMNS_ = 8>
class MatrixMultiplexer
{
private:
	using SIPO_TYPE = SIPO<CLOCK, LATCH, DATA>;
	using TRAIT = MATRIX_TRAIT<COLUMNS_, ROWS_>;

	static_assert(TRAIT::SUPPORTED, "Provided COLUMNS_ and ROWS_ template parameters are not supported");

public:
	using ROW_TYPE = typename TRAIT::ROW_TYPE;
	static constexpr const uint8_t ROWS = ROWS_;
	static constexpr const uint8_t COLUMNS = COLUMNS_;

	static constexpr const Board::Port PORT = SIPO_TYPE::PORT;
	static constexpr const uint8_t DDR_MASK = SIPO_TYPE::DDR_MASK;
	static constexpr const uint8_t PORT_MASK = SIPO_TYPE::PORT_MASK;

	MatrixMultiplexer():_data(), _blinks(), _row(), _blink_count() {}

	inline void init()
	{
		_sipo.init();
	}
	inline ROW_TYPE* data()
	{
		return _data;
	}

	// if 0, that means this pixel shall blink, if 1 it shall never blink
	// only lit pixels can blink, dark pixels never blink
	inline ROW_TYPE* blinks()
	{
		return _blinks;
	}

	void refresh(BlinkMode blink_mode)
	{
		ROW_TYPE data = _data[_row];
		if (blink_mode != BlinkMode::NO_BLINK)
		{
			if (_blink_count > BLINK_COUNT / ROWS)
			{
				if (blink_mode == BlinkMode::BLINK_BLINKABLE_DATA || blink_mode == BlinkMode::BLINK_ALL_BLINKS)
					data &= ~_blinks[_row];
				else
					data = 0;
			}
			else if (blink_mode == BlinkMode::BLINK_ALL_BLINKS)
				data |= _blinks[_row];
		}
		//FIXME Adapt to work on any ROW/COLUMN size
		_sipo.output(TRAIT::as_type(~_BV(_row), data));
//		_sipo.output(as_uint16_t(_BV(_row) ^ 0xFF, data));
		if (++_row == ROWS)
		{
			_row = 0;
			if (blink_mode != BlinkMode::NO_BLINK && ++_blink_count == 2 * BLINK_COUNT / ROWS)
				_blink_count = 0;
		}
	}

	// Refreshes the next row of LED without any blinking
	// This is equivalent to refresh(BlinkMode::NO_BLINK) but smaller and faster
	void refresh()
	{
		//FIXME Adapt to work on any ROW/COLUMN size
		_sipo.output(TRAIT::as_type(~_BV(_row), _data[_row]));
//		_sipo.output(as_uint16_t(_BV(_row) ^ 0xFF, _data[_row]));
		if (++_row == ROWS)
			_row = 0;
	}

	void clear()
	{
		//FIXME Adapt to work on any ROW/COLUMN size
		_sipo.output(TRAIT::as_type(0, 0));
//		_sipo.output(uint16_t(0));
	}

protected:
	SIPO<CLOCK, LATCH, DATA> _sipo;
	ROW_TYPE _data[ROWS];
	ROW_TYPE _blinks[ROWS];
	uint8_t _row;
	uint16_t _blink_count;
};

#endif /* MULTIPLEXER_HH */

<commit_msg>Conway cleanup source code.<commit_after>#ifndef MULTIPLEXER_HH
#define MULTIPLEXER_HH

#include <fastarduino/devices/SIPO.hh>

enum class BlinkMode: uint8_t
{
	// In this mode, no blink occurs at all
	NO_BLINK = 0,
	// In this mode, blink is done for LEDs that are ON (in _data), whatever _blinks content
	BLINK_ALL_DATA,
	// In this mode, blink is done for LEDs that are set to blink (in _blinks), whatever if they're ON or not (in _data)
	BLINK_ALL_BLINKS,
	// In this mode, blink is done for LEDs that are ON (in _data) and set to blink (in _blinks)
	BLINK_BLINKABLE_DATA
};

// Special "traits" used by Multiplexer to determine, at compile time, its behavior based on the number of
// ROWS and COLUMNS
template<uint8_t ROWS_, uint8_t COLUMNS_>
struct MATRIX_TRAIT
{
	using COLUMN_TYPE = uint8_t;
	using ROW_TYPE = uint8_t;
	using TYPE = uint16_t;
	static TYPE as_type(COLUMN_TYPE column, ROW_TYPE row);
	static constexpr const bool SUPPORTED = false;
};

template<typename ROW_TYPE_, typename COLUMN_TYPE_, typename TYPE_>
struct MATRIX_TRAIT_IMPL
{
	using COLUMN_TYPE = COLUMN_TYPE_;
	using ROW_TYPE = ROW_TYPE_;
	using TYPE = TYPE_;
	static TYPE as_type(COLUMN_TYPE column, ROW_TYPE row)
	{
		return ((TYPE(column)) << (8 * sizeof(ROW_TYPE))) | TYPE(row);
	}
	static constexpr const bool SUPPORTED = true;
};

template<> struct MATRIX_TRAIT<8, 8>: MATRIX_TRAIT_IMPL<uint8_t, uint8_t, uint16_t> {};
template<> struct MATRIX_TRAIT<16, 16>: MATRIX_TRAIT_IMPL<uint16_t, uint16_t, uint32_t> {};
//TODO other template for more special cases: 16+8, 8+16, 24+8...

//TODO do we need BLINK_COUNT as class template argument, or just as method template argument?

template<	Board::DigitalPin CLOCK,
			Board::DigitalPin LATCH,
			Board::DigitalPin DATA,
			uint16_t BLINK_COUNT = 16,
			uint8_t ROWS_ = 8,
			uint8_t COLUMNS_ = 8>
class MatrixMultiplexer
{
private:
	using SIPO_TYPE = SIPO<CLOCK, LATCH, DATA>;
	using TRAIT = MATRIX_TRAIT<COLUMNS_, ROWS_>;

	static_assert(TRAIT::SUPPORTED, "Provided COLUMNS_ and ROWS_ template parameters are not supported");

public:
	using ROW_TYPE = typename TRAIT::ROW_TYPE;
	static constexpr const uint8_t ROWS = ROWS_;
	static constexpr const uint8_t COLUMNS = COLUMNS_;

	static constexpr const Board::Port PORT = SIPO_TYPE::PORT;
	static constexpr const uint8_t DDR_MASK = SIPO_TYPE::DDR_MASK;
	static constexpr const uint8_t PORT_MASK = SIPO_TYPE::PORT_MASK;

	MatrixMultiplexer():_data(), _blinks(), _row(), _blink_count() {}

	inline void init()
	{
		_sipo.init();
	}
	inline ROW_TYPE* data()
	{
		return _data;
	}

	// if 0, that means this pixel shall blink, if 1 it shall never blink
	// only lit pixels can blink, dark pixels never blink
	inline ROW_TYPE* blinks()
	{
		return _blinks;
	}

	void refresh(BlinkMode blink_mode)
	{
		ROW_TYPE data = _data[_row];
		if (blink_mode != BlinkMode::NO_BLINK)
		{
			if (_blink_count > BLINK_COUNT / ROWS)
			{
				if (blink_mode == BlinkMode::BLINK_BLINKABLE_DATA || blink_mode == BlinkMode::BLINK_ALL_BLINKS)
					data &= ~_blinks[_row];
				else
					data = 0;
			}
			else if (blink_mode == BlinkMode::BLINK_ALL_BLINKS)
				data |= _blinks[_row];
		}
		_sipo.output(TRAIT::as_type(~_BV(_row), data));
		if (++_row == ROWS)
		{
			_row = 0;
			if (blink_mode != BlinkMode::NO_BLINK && ++_blink_count == 2 * BLINK_COUNT / ROWS)
				_blink_count = 0;
		}
	}

	// Refreshes the next row of LED without any blinking
	// This is equivalent to refresh(BlinkMode::NO_BLINK) but smaller and faster
	void refresh()
	{
		_sipo.output(TRAIT::as_type(~_BV(_row), _data[_row]));
		if (++_row == ROWS)
			_row = 0;
	}

	void clear()
	{
		_sipo.output(TRAIT::as_type(0, 0));
	}

protected:
	SIPO<CLOCK, LATCH, DATA> _sipo;
	ROW_TYPE _data[ROWS];
	ROW_TYPE _blinks[ROWS];
	uint8_t _row;
	uint16_t _blink_count;
};

#endif /* MULTIPLEXER_HH */

<|endoftext|>


<commit_before>/*

This file is part of VROOM.

Copyright (c) 2015-2018, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include <cassert>
#include <limits>
#include <list>
#include <set>

#include "algorithms/munkres.h"
#include "structures/abstract/edge.h"

template <class T>
std::unordered_map<index_t, index_t>
minimum_weight_perfect_matching(const matrix<T>& m) {

  // Trivial initial labeling.
  std::unordered_map<index_t, T> labeling_x;
  std::unordered_map<index_t, T> labeling_y;
  for (index_t i = 0; i < m.size(); ++i) {
    labeling_y.emplace(i, 0);
    T min_weight = std::numeric_limits<T>::max();
    for (index_t j = 0; j < m.size(); ++j) {
      if (m[i][j] < min_weight) {
        min_weight = m[i][j];
      }
    }
    labeling_x.emplace(i, min_weight);
  }

  // Initial empty matching.
  std::unordered_map<index_t, index_t> matching_xy;
  std::unordered_map<index_t, index_t> matching_yx;

  // Alternating tree.
  std::unordered_map<index_t, index_t> alternating_tree;

  while (matching_xy.size() < m.size()) {
    // Step 1.

    alternating_tree.clear();
    std::set<index_t> S;
    std::set<index_t> T_set;

    // Finding any unmatched x.
    index_t unmatched_x = 0;
    while (matching_xy.find(unmatched_x) != matching_xy.end()) {
      ++unmatched_x;
    }
    S.insert(unmatched_x);

    // Saving relevant neighbors in equality graph in alternating_tree
    // and initializing slacks.
    std::vector<T> slack;
    slack.resize(m.size());
    for (index_t y = 0; y < m.size(); ++y) {
      if (labeling_x.at(unmatched_x) + labeling_y.at(y) == m[unmatched_x][y]) {
        alternating_tree.emplace(y, unmatched_x);
      }
      slack[y] = m[unmatched_x][y] - labeling_x.at(unmatched_x) -
                      labeling_y.at(y);
    }

    bool augmented_path = false;

    while (!augmented_path) {
      // Test if neighbors of S in equality graph equals T_set or not
      // (note that T_set is included in S neighbors).
      if (alternating_tree.size() == T_set.size()) {
        // Step 2.

        T alpha = std::numeric_limits<T>::max();
        for (index_t y = 0; y < m.size(); ++y) {
          // Computing alpha, the minimum of slack values over
          // complement of T_set.
          if (T_set.find(y) == T_set.end()) {
            T current_slack = slack[y];
            if (current_slack < alpha) {
              alpha = current_slack;
            }
          }
        }

        // Update labelings
        for (auto const& x : S) {
          labeling_x.at(x) = labeling_x.at(x) + alpha;
        }
        for (auto const& y : T_set) {
          labeling_y.at(y) = labeling_y.at(y) - alpha;
        }

        // Updating relevant neighbors in new equality graph and
        // updating slacks.
        for (index_t y = 0; y < m.size(); ++y) {
          if (T_set.find(y) == T_set.end()) {
            slack[y] = slack[y] - alpha;

            if (alternating_tree.find(y) == alternating_tree.end()) {
              for (auto const& x : S) {
                if (labeling_x.at(x) + labeling_y.at(y) == m[x][y]) {
                    alternating_tree.emplace(y, x);
                }
              }
            }
          }
        }
      }

      // Step 3.

      // First y in equality neighbors not in T_set.
      index_t chosen_y;
      for (auto const& edge : alternating_tree) {
        if (T_set.find(edge.first) == T_set.end()) {
          // MUST happen before endge reaches the end of
          // alternating_tree.
          chosen_y = edge.first;
          break;
        }
      }

      auto matching_y = matching_yx.find(chosen_y);
      if (matching_y != matching_yx.end()) {
        // Chosen y is actually matched in M, update S and T_set and
        // proceed to step 2.
        index_t matched_x = matching_y->second;

        S.insert(matched_x);
        T_set.insert(chosen_y);

        // Updating slacks.
        for (index_t y = 0; y < m.size(); ++y) {
          T current_value = slack[y];
          T new_value =
            m[matched_x][y] - labeling_x.at(matched_x) - labeling_y.at(y);
          if (new_value < current_value) {
            slack[y] = new_value;
          }
        }
      } else {
        // Find larger matching using M-alternating path. The path is
        // described at each step by:
        //
        // chosen_y -- chosen_x -- next_y -- [...] -- unmatched_x
        //
        // where (chosen_x, next_y) is already in matching and should
        // be removed and (chosen_x, chosen_y) is to be added.

        index_t current_y = chosen_y;
        index_t current_x = alternating_tree.at(current_y);

        while (current_x != unmatched_x) {
          index_t next_y = matching_xy.at(current_x);

          // Remove alternating edge from current matching.
          matching_xy.erase(matching_xy.find(current_x));
          matching_yx.erase(matching_yx.find(next_y));

          // Add edge from alternating tree to matching.
          matching_xy.emplace(current_x, current_y);
          matching_yx.emplace(current_y, current_x);

          current_y = next_y;
          current_x = alternating_tree.at(current_y);
        }
        // Adding last edge from alternating tree.
        matching_xy.emplace(current_x, current_y);
        matching_yx.emplace(current_y, current_x);

        // Back to step 1.
        augmented_path = true;
      }
    }
  }
  return matching_xy;
}

template <class T>
std::unordered_map<index_t, index_t>
greedy_symmetric_approx_mwpm(const matrix<T>& m) {
  // Fast greedy algorithm for finding a symmetric perfect matching,
  // choosing always smaller possible value, no minimality
  // assured. Matrix size should be even!
  assert(m.size() % 2 == 0);

  std::unordered_map<index_t, index_t> matching;
  std::set<index_t> remaining_indices;
  for (index_t i = 0; i < m.size(); ++i) {
    remaining_indices.insert(i);
  }

  while (remaining_indices.size() > 0) {
    T min_weight = std::numeric_limits<T>::max();
    index_t first_chosen_index;
    index_t second_chosen_index;
    std::set<index_t>::iterator chosen_i;
    std::set<index_t>::iterator chosen_j;
    for (auto i = remaining_indices.begin(); i != remaining_indices.end();
         ++i) {
      auto j = i;
      ++j;
      for (; j != remaining_indices.end(); ++j) {
        T current_weight = m[*i][*j];
        if (current_weight < min_weight) {
          min_weight = current_weight;
          first_chosen_index = *i;
          second_chosen_index = *j;
          chosen_i = i;
          chosen_j = j;
        }
      }
    }
    matching.emplace(first_chosen_index, second_chosen_index);
    remaining_indices.erase(chosen_j);
    remaining_indices.erase(chosen_i);
  }

  return matching;
}

template std::unordered_map<index_t, index_t>
minimum_weight_perfect_matching(const matrix<cost_t>& m);

template std::unordered_map<index_t, index_t>
greedy_symmetric_approx_mwpm(const matrix<cost_t>& m);
<commit_msg>Replace ordered with unordered_sets<commit_after>/*

This file is part of VROOM.

Copyright (c) 2015-2018, Julien Coupey.
All rights reserved (see LICENSE).

*/

#include <cassert>
#include <limits>
#include <list>
#include <set>

#include "algorithms/munkres.h"
#include "structures/abstract/edge.h"

template <class T>
std::unordered_map<index_t, index_t>
minimum_weight_perfect_matching(const matrix<T>& m) {

  // Trivial initial labeling.
  std::unordered_map<index_t, T> labeling_x;
  std::unordered_map<index_t, T> labeling_y;
  for (index_t i = 0; i < m.size(); ++i) {
    labeling_y.emplace(i, 0);
    T min_weight = std::numeric_limits<T>::max();
    for (index_t j = 0; j < m.size(); ++j) {
      if (m[i][j] < min_weight) {
        min_weight = m[i][j];
      }
    }
    labeling_x.emplace(i, min_weight);
  }

  // Initial empty matching.
  std::unordered_map<index_t, index_t> matching_xy;
  std::unordered_map<index_t, index_t> matching_yx;

  // Alternating tree.
  std::unordered_map<index_t, index_t> alternating_tree;

  while (matching_xy.size() < m.size()) {
    // Step 1.

    alternating_tree.clear();
    std::unordered_set<index_t> S;
    std::unordered_set<index_t> T_set;

    // Finding any unmatched x.
    index_t unmatched_x = 0;
    while (matching_xy.find(unmatched_x) != matching_xy.end()) {
      ++unmatched_x;
    }
    S.insert(unmatched_x);

    // Saving relevant neighbors in equality graph in alternating_tree
    // and initializing slacks.
    std::vector<T> slack;
    slack.resize(m.size());
    for (index_t y = 0; y < m.size(); ++y) {
      if (labeling_x.at(unmatched_x) + labeling_y.at(y) == m[unmatched_x][y]) {
        alternating_tree.emplace(y, unmatched_x);
      }
      slack[y] = m[unmatched_x][y] - labeling_x.at(unmatched_x) -
                      labeling_y.at(y);
    }

    bool augmented_path = false;

    while (!augmented_path) {
      // Test if neighbors of S in equality graph equals T_set or not
      // (note that T_set is included in S neighbors).
      if (alternating_tree.size() == T_set.size()) {
        // Step 2.

        T alpha = std::numeric_limits<T>::max();
        for (index_t y = 0; y < m.size(); ++y) {
          // Computing alpha, the minimum of slack values over
          // complement of T_set.
          if (T_set.find(y) == T_set.end()) {
            T current_slack = slack[y];
            if (current_slack < alpha) {
              alpha = current_slack;
            }
          }
        }

        // Update labelings
        for (auto const& x : S) {
          labeling_x.at(x) = labeling_x.at(x) + alpha;
        }
        for (auto const& y : T_set) {
          labeling_y.at(y) = labeling_y.at(y) - alpha;
        }

        // Updating relevant neighbors in new equality graph and
        // updating slacks.
        for (index_t y = 0; y < m.size(); ++y) {
          if (T_set.find(y) == T_set.end()) {
            slack[y] = slack[y] - alpha;

            if (alternating_tree.find(y) == alternating_tree.end()) {
              for (auto const& x : S) {
                if (labeling_x.at(x) + labeling_y.at(y) == m[x][y]) {
                    alternating_tree.emplace(y, x);
                }
              }
            }
          }
        }
      }

      // Step 3.

      // First y in equality neighbors not in T_set.
      index_t chosen_y;
      for (auto const& edge : alternating_tree) {
        if (T_set.find(edge.first) == T_set.end()) {
          // MUST happen before endge reaches the end of
          // alternating_tree.
          chosen_y = edge.first;
          break;
        }
      }

      auto matching_y = matching_yx.find(chosen_y);
      if (matching_y != matching_yx.end()) {
        // Chosen y is actually matched in M, update S and T_set and
        // proceed to step 2.
        index_t matched_x = matching_y->second;

        S.insert(matched_x);
        T_set.insert(chosen_y);

        // Updating slacks.
        for (index_t y = 0; y < m.size(); ++y) {
          T current_value = slack[y];
          T new_value =
            m[matched_x][y] - labeling_x.at(matched_x) - labeling_y.at(y);
          if (new_value < current_value) {
            slack[y] = new_value;
          }
        }
      } else {
        // Find larger matching using M-alternating path. The path is
        // described at each step by:
        //
        // chosen_y -- chosen_x -- next_y -- [...] -- unmatched_x
        //
        // where (chosen_x, next_y) is already in matching and should
        // be removed and (chosen_x, chosen_y) is to be added.

        index_t current_y = chosen_y;
        index_t current_x = alternating_tree.at(current_y);

        while (current_x != unmatched_x) {
          index_t next_y = matching_xy.at(current_x);

          // Remove alternating edge from current matching.
          matching_xy.erase(matching_xy.find(current_x));
          matching_yx.erase(matching_yx.find(next_y));

          // Add edge from alternating tree to matching.
          matching_xy.emplace(current_x, current_y);
          matching_yx.emplace(current_y, current_x);

          current_y = next_y;
          current_x = alternating_tree.at(current_y);
        }
        // Adding last edge from alternating tree.
        matching_xy.emplace(current_x, current_y);
        matching_yx.emplace(current_y, current_x);

        // Back to step 1.
        augmented_path = true;
      }
    }
  }
  return matching_xy;
}

template <class T>
std::unordered_map<index_t, index_t>
greedy_symmetric_approx_mwpm(const matrix<T>& m) {
  // Fast greedy algorithm for finding a symmetric perfect matching,
  // choosing always smaller possible value, no minimality
  // assured. Matrix size should be even!
  assert(m.size() % 2 == 0);

  std::unordered_map<index_t, index_t> matching;
  std::set<index_t> remaining_indices;
  for (index_t i = 0; i < m.size(); ++i) {
    remaining_indices.insert(i);
  }

  while (remaining_indices.size() > 0) {
    T min_weight = std::numeric_limits<T>::max();
    index_t first_chosen_index;
    index_t second_chosen_index;
    std::set<index_t>::iterator chosen_i;
    std::set<index_t>::iterator chosen_j;
    for (auto i = remaining_indices.begin(); i != remaining_indices.end();
         ++i) {
      auto j = i;
      ++j;
      for (; j != remaining_indices.end(); ++j) {
        T current_weight = m[*i][*j];
        if (current_weight < min_weight) {
          min_weight = current_weight;
          first_chosen_index = *i;
          second_chosen_index = *j;
          chosen_i = i;
          chosen_j = j;
        }
      }
    }
    matching.emplace(first_chosen_index, second_chosen_index);
    remaining_indices.erase(chosen_j);
    remaining_indices.erase(chosen_i);
  }

  return matching;
}

template std::unordered_map<index_t, index_t>
minimum_weight_perfect_matching(const matrix<cost_t>& m);

template std::unordered_map<index_t, index_t>
greedy_symmetric_approx_mwpm(const matrix<cost_t>& m);
<|endoftext|>


<commit_before>#include <scriptzeug/ScriptContext.h>
#include <scriptzeug/Backend/AbstractScriptContext.h>
#include "BackendDuktape/DuktapeScriptContext.h"
#ifdef LIBZEUG_USE_V8
    #include "BackendJavaScript/JSScriptContext.h"
#endif

using namespace reflectionzeug;
namespace scriptzeug
{

ScriptContext::ScriptContext(const std::string & backend)
: m_backend(nullptr)
{
    // Create backend
    if (backend == "duktape")
        m_backend = new DuktapeScriptContext(this);

#ifdef LIBZEUG_USE_V8
    if (backend == "javascript")
        m_backend = new JSScriptContext(this);
#endif
}

ScriptContext::~ScriptContext()
{
    // Release backend
    if (m_backend)
        delete m_backend;
}

void ScriptContext::registerObject(reflectionzeug::PropertyGroup * obj)
{
    if (m_backend)
        m_backend->registerObject(obj);
}

Variant ScriptContext::evaluate(const std::string & code)
{
    if (m_backend)
        return m_backend->evaluate(code);
    else
        return Variant();
}

} // namespace scriptzeug
<commit_msg>Make "duktape" the default javascript backend<commit_after>#include <scriptzeug/ScriptContext.h>
#include <scriptzeug/Backend/AbstractScriptContext.h>
#include "BackendDuktape/DuktapeScriptContext.h"
#ifdef LIBZEUG_USE_V8
    #include "BackendJavaScript/JSScriptContext.h"
#endif

using namespace reflectionzeug;
namespace scriptzeug
{

ScriptContext::ScriptContext(const std::string & backend)
: m_backend(nullptr)
{
    // Create backend

    // Javascript (default: duktape)

    // Duktape
    if (backend == "duktape" || backend == "javascript" || backend == "js") {
        m_backend = new DuktapeScriptContext(this);
    }

    // V8
#ifdef LIBZEUG_USE_V8
    else if (backend == "v8") {
        m_backend = new JSScriptContext(this);
    }
#endif
}

ScriptContext::~ScriptContext()
{
    // Release backend
    if (m_backend)
        delete m_backend;
}

void ScriptContext::registerObject(reflectionzeug::PropertyGroup * obj)
{
    if (m_backend)
        m_backend->registerObject(obj);
}

Variant ScriptContext::evaluate(const std::string & code)
{
    if (m_backend)
        return m_backend->evaluate(code);
    else
        return Variant();
}

} // namespace scriptzeug
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////
//  Button.cpp
//  Implementation of the Class Button
//  Created on:      02-Mar-2015 9:17:12 PM
///////////////////////////////////////////////////////////

#include "Button.h"

Button::Button(unsigned char textSize){
	contents = Text(textSize);
}

Button::Button(unsigned int width, unsigned int height, int backgroundColor, int textColor, int borderColor,unsigned char textSize){
	//if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	if(label = (char *)malloc(DISPLAY_SIZE+1)) memset(label,0,DISPLAY_SIZE+1);

	x = 0;
	y = 0;
	contents = Text(textSize);
	this->setSize(width,height);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = false;
	init();
}

Button::Button(unsigned int radius, int backgroundColor, int textColor, int borderColor){
	//if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	if(label = (char *)malloc(DISPLAY_SIZE+1)) memset(label,0,DISPLAY_SIZE+1);
	contents = Text();
	x = radius;
	y = radius;
	this->setSize(2*radius,2*radius);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = true;
	init();
}

Button::~Button(){
	free(contents.text);
}

/*
 * Initialization of several common parameters
 */
void Button::init(){
	type = 0x30;
	isButton = true;
	touched = false;
	borderWidth = 2;
	debounceTime = DEBOUNCE;
	lastMillis = millis();
}

int Button::getLabelSize(){
	if(*label){
		return contents.getTextLength(label)*6*borderWidth + 6;
	}
	return 0;
}

void Button::drawBackground(int color){
	int labelSize = getLabelSize();
	int xl;
	int wl;
	if(labelPos == 1){

	}else if(labelPos == 2){
		xl = x;// + labelSize;
		wl = w + labelSize;
	}else if(labelPos == 3){

	}else{
		xl = x + labelSize;
		wl = w + labelSize;
	}
	//Fill background

	if(!isRound){
		Tft.fillRect(x+borderWidth, y+borderWidth, wl-(2*borderWidth)+1,h-(2*borderWidth)+1,color);
	}else{
		int radius = (w>>1)-borderWidth;
		Tft.fillCircle(xl+radius+borderWidth,y+radius+borderWidth,radius,color);
		// label background
		Tft.fillRect(xl+2*radius+2*borderWidth+FONT_SPACE, y+borderWidth, labelSize-(2*borderWidth),h-(2*borderWidth),this->myCanvas->bgColor);
	}
}

void Button::drawBorder(){
	int labelSize = getLabelSize();
	int xl;

	if(labelPos == 1){

	}else if(labelPos == 2){
		xl = x;// + labelSize;

	}else if(labelPos == 3){

	}else{
		xl = x + labelSize;

	}

	int xPos = xl;
	int width = w;
	int yPos = y;
	uint8_t height = h;

	for(byte i=borderWidth; i!=0;i--){
		if(!isRound){
			Tft.drawRectangle(xPos++,yPos++,width--,height--,borderColor);
			width--;
			height--;
		}else{
			int radius = width>>1;
			Tft.drawCircle(xl+radius,y+radius,(radius)-i,borderColor);
		}
	}
}

void Button::drawText(){
	int xl=0;
	int yl=0;
	int labelSize=getLabelSize();

	//Serial.print("Label: ");Serial.println(label);

	if(labelSize > 0){
		if(labelPos == 1){ // top

		}else if(labelPos == 2){ // right
			xl = x + w + FONT_SPACE;
			yl = y+(h-8*fontSize)/2;
		}else if(labelPos == 3){ // bottom

		}else{ 	// default 0-left
			xl = x;
			yl = y+(h-8*fontSize)/2;
		}
		//Serial.print("labelPos: ");Serial.println(labelPos);
		//Serial.print("label size: ");Serial.println(labelSize);

		Tft.drawString(label,xl,yl,fontSize,WHITE);
	}

	//Count characters to center on the button - Nice trick from the Tft2 library
	if(*contents.text){
		char size = contents.getTextSize();
		/*
		char size = 0;
		char* chars = text;
		while(*chars){
			*chars++;
			size++;
		}
		*/
		//Calculate centered position of the text
		int stringX = x+labelSize+(w-size*6*fontSize)/2;
		int stringY = y+(h-8*fontSize)/2;
		Tft.drawString(contents.text,stringX,stringY,fontSize,fgColor);
	}
}

/*
void Button::clear(){
	byte textSize = getTextSize();
	if(textSize){
		for(int i = textSize-1; i >= 0; i--)
		{
				text[i] = 0;
		}
	}
}
*/

unsigned char Button::getTextLength(char* c){
	return contents.getTextLength(c);
	/*
	char size = 0;
	if(*c){
    char* chars = c;
    while(*chars){
      *chars++;
      size++;
    }
  }
  return size;
	*/
}

unsigned char Button::getTextSize(){
  //return getTextLength(text);
	return contents.getTextSize();
}

void Button::setDebounce(unsigned int d){
	debounceTime = d;
}

/**
 * Sets the event handler: The function that should be called whenever the touched
 * event is detected.
 */
void Button::setEventHandler(void (*functionPointer)(Button *)){
	eventHandler = functionPointer;
}

/**
 * Shows the widget on the screen. This method must be overriden by the widget to
 * show the particular widget. It should be a pure virtual function: (i.e. virtual
 * void function() = 0;
 */
void Button::show(){
	drawBackground(bgColor);
	update();
}

void Button::setNum(int num){
	if(contents.getNum()==num)return;
	contents.clear();
	contents.setNum(num);
	/*
	clear();
	//Serial.println("Text cleared in setNum");Serial.print("Num to be processed: ");Serial.println(num);
	char numChar[DISPLAY_SIZE];
	char chars = 0;

	while(num > 0)	// Extract characters representing the powers of ten
	{
		numChar[chars++] = '0'+num%10;
		num /= 10;
		//Serial.print("Num after loop: ");Serial.println(numChar[chars-1]);
	}

	// Reverse the order of the characters
	for(int j = chars-1; j >= 0; j--)//DISPLAY_SIZE; j++)
	{
		text[j] = numChar[chars-1-j];
	}
	text[chars]=0;

	//Serial.print("Num entered: ");Serial.println(text);
	//drawBackground(bgColor);
	//update();
	*/
}

void Button::setText(char* _text){
  contents.text = _text;
}

void Button::setLabel(char* _label){
  label = _label;
}

char* Button::getText(){
  return contents.text;
}

long Button::getNum(){
	/*
	char size = getTextSize();
	long result = 0;
	for(int i = 0; i<size; i++){
		if(text[i] == '.') break;  // Only process integer side
		result = result * 10 + text[i]-'0';
	}
	return result;
	*/
	return contents.getNum();
}

void Button::fitToText(){
  if(*contents.text){
	char size = contents.getTextSize();
	/*
    char* chars = text;
    char size = 0;
    while(*chars){
      *chars++;
      size++;
    }
	*/
    w = size * 6 * borderWidth + 6;
    h = 8 * borderWidth + 8;
    //drawString(text,x+5,y+5,2,textColor);
  }
}

//Overriden methods
/**
 * Check if the touched point is within bounds of this widget.
 */
bool Button::checkTouch(Point* p){
	int labelSize = getLabelSize();
	int xl;

	if(labelPos == 1){

	}else if(labelPos == 2){
		xl = x;
	}else if(labelPos == 3){

	}else{
		xl = x + labelSize;
	}
	//Serial.print("Checking button ");Serial.println(text);
	if(lastMillis + debounceTime < millis()){
		if((p->x > xl) && (p->x < xl+w) && (p->y > y) && (p->y < y+h)){
			touched = !touched;
			eventHandler(this);
			lastMillis = millis();
			//block = true;
			//Serial.print("Button ");Serial.print(text);Serial.println(" pressed");
			return false;
		}
	}
	// if block is true return false, so canvas will not continue to
	// process the event.
	return !block;
}

/*
 * This is the update() method.
 */
void Button::update(){
	//drawBackground(bgColor);
	drawText();
	drawBorder();
}

/*
 * This method is called by the canvas and passes a pointer to it.
 * The button class uses this pointer to get a pointer to the
 * touched point, if any, and calls the checkTouch routine to detect
 * if the button was touched.
 */
/*void Button::update(Canvas* c){
	checkTouch(c->touchedPoint);
}*/
<commit_msg>Commented out code that filled the label's background when the drawBackground was invoked.<commit_after>///////////////////////////////////////////////////////////
//  Button.cpp
//  Implementation of the Class Button
//  Created on:      02-Mar-2015 9:17:12 PM
///////////////////////////////////////////////////////////

#include "Button.h"

Button::Button(unsigned char textSize){
	contents = Text(textSize);
}

Button::Button(unsigned int width, unsigned int height, int backgroundColor, int textColor, int borderColor,unsigned char textSize){
	//if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	if(label = (char *)malloc(DISPLAY_SIZE+1)) memset(label,0,DISPLAY_SIZE+1);

	x = 0;
	y = 0;
	contents = Text(textSize);
	this->setSize(width,height);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = false;
	init();
}

Button::Button(unsigned int radius, int backgroundColor, int textColor, int borderColor){
	//if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	if(label = (char *)malloc(DISPLAY_SIZE+1)) memset(label,0,DISPLAY_SIZE+1);

	x = radius;
	y = radius;
	contents = Text(8);
	this->setSize(2*radius,2*radius);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = true;
	init();
}

Button::~Button(){
	free(contents.text);
}

/*
 * Initialization of several common parameters
 */
void Button::init(){
	type = 0x30;
	isButton = true;
	touched = false;
	borderWidth = 2;
	debounceTime = DEBOUNCE;
	lastMillis = millis();
}

int Button::getLabelSize(){
	if(*label){
		return contents.getTextLength(label)*6*borderWidth + 6;
	}
	return 0;
}

void Button::drawBackground(int color){
	int labelSize = getLabelSize();
	int xl;
	int wl;
	if(labelPos == 1){

	}else if(labelPos == 2){
		xl = x;// + labelSize;
		wl = w + labelSize;
	}else if(labelPos == 3){

	}else{
		xl = x + labelSize;
		wl = w + labelSize;
	}
	//Fill background

	if(!this->isRound){
		Tft.fillRect(x+borderWidth, y+borderWidth, wl-(2*borderWidth)+1,h-(2*borderWidth)+1,color);
	}else{
		int radius = (w>>1)-borderWidth;
		Tft.fillCircle(xl+radius+borderWidth,y+radius+borderWidth,radius-borderWidth/2,color);
		// label background
		//Tft.fillRect(xl+2*radius+2*borderWidth+FONT_SPACE, y+borderWidth, labelSize-(2*borderWidth),h-(2*borderWidth),this->myCanvas->bgColor);
		//Tft.fillRect(x, y+borderWidth, labelSize-(2*borderWidth),h-(2*borderWidth),BLACK);
	}
}

void Button::drawBorder(){
	int labelSize = getLabelSize();
	int xl;

	if(labelPos == 1){

	}else if(labelPos == 2){
		xl = x;// + labelSize;

	}else if(labelPos == 3){

	}else{
		xl = x + labelSize;

	}

	int xPos = xl;
	int width = w;
	int yPos = y;
	uint8_t height = h;

	for(byte i=borderWidth; i!=0;i--){
		if(!this->isRound){
			Tft.drawRectangle(xPos++,yPos++,width--,height--,borderColor);
			width--;
			height--;
		}else{
			int radius = width>>1;
			Tft.drawCircle(xl+radius,y+radius,(radius)-i,borderColor);
		}
	}
}

void Button::drawText(){
	int xl=0;
	int yl=0;
	int labelSize=getLabelSize();

	//Serial.print("Label: ");Serial.println(label);

	if(labelSize > 0){
		if(labelPos == 1){ // top

		}else if(labelPos == 2){ // right
			xl = x + w + FONT_SPACE;
			yl = y+(h-8*fontSize)/2;
		}else if(labelPos == 3){ // bottom

		}else{ 	// default 0-left
			xl = x;
			yl = y+(h-8*fontSize)/2;
		}
		//Serial.print("labelPos: ");Serial.println(labelPos);
		//Serial.print("label size: ");Serial.println(labelSize);

		Tft.drawString(label,xl,yl,fontSize,fgColor);
	}

	//Count characters to center on the button - Nice trick from the Tft2 library
	if(*contents.text){
		char size = contents.getTextSize();
		/*
		char size = 0;
		char* chars = text;
		while(*chars){
			*chars++;
			size++;
		}
		*/
		//Calculate centered position of the text
		int stringX = x+labelSize+(w-size*6*fontSize)/2;
		int stringY = y+(h-8*fontSize)/2;
		Tft.drawString(contents.text,stringX,stringY,fontSize,fgColor);
	}
}

/*
void Button::clear(){
	byte textSize = getTextSize();
	if(textSize){
		for(int i = textSize-1; i >= 0; i--)
		{
				text[i] = 0;
		}
	}
}
*/

unsigned char Button::getTextLength(char* c){
	return contents.getTextLength(c);
	/*
	char size = 0;
	if(*c){
    char* chars = c;
    while(*chars){
      *chars++;
      size++;
    }
  }
  return size;
	*/
}

unsigned char Button::getTextSize(){
  //return getTextLength(text);
	return contents.getTextSize();
}

void Button::setDebounce(unsigned int d){
	debounceTime = d;
}

/**
 * Sets the event handler: The function that should be called whenever the touched
 * event is detected.
 */
void Button::setEventHandler(void (*functionPointer)(Button *)){
	eventHandler = functionPointer;
}

/**
 * Shows the widget on the screen. This method must be overriden by the widget to
 * show the particular widget. It should be a pure virtual function: (i.e. virtual
 * void function() = 0;
 */
void Button::show(){
	drawBackground(bgColor);
	update();
}

void Button::setNum(int num){
	if(contents.getNum()==num)return;
	contents.clear();
	contents.setNum(num);
	/*
	clear();
	//Serial.println("Text cleared in setNum");Serial.print("Num to be processed: ");Serial.println(num);
	char numChar[DISPLAY_SIZE];
	char chars = 0;

	while(num > 0)	// Extract characters representing the powers of ten
	{
		numChar[chars++] = '0'+num%10;
		num /= 10;
		//Serial.print("Num after loop: ");Serial.println(numChar[chars-1]);
	}

	// Reverse the order of the characters
	for(int j = chars-1; j >= 0; j--)//DISPLAY_SIZE; j++)
	{
		text[j] = numChar[chars-1-j];
	}
	text[chars]=0;

	//Serial.print("Num entered: ");Serial.println(text);
	//drawBackground(bgColor);
	//update();
	*/
}

void Button::setText(char* _text){
  contents.text = _text;
}

void Button::setLabel(char* _label){
  label = _label;
}

char* Button::getText(){
  return contents.text;
}

long Button::getNum(){
	/*
	char size = getTextSize();
	long result = 0;
	for(int i = 0; i<size; i++){
		if(text[i] == '.') break;  // Only process integer side
		result = result * 10 + text[i]-'0';
	}
	return result;
	*/
	return contents.getNum();
}

void Button::fitToText(){
  if(*contents.text){
	char size = contents.getTextSize();
	/*
    char* chars = text;
    char size = 0;
    while(*chars){
      *chars++;
      size++;
    }
	*/
    w = size * 6 * borderWidth + 6;
    h = 8 * borderWidth + 8;
    //drawString(text,x+5,y+5,2,textColor);
  }
}

//Overriden methods
/**
 * Check if the touched point is within bounds of this widget.
 */
bool Button::checkTouch(Point* p){
	int labelSize = getLabelSize();
	int xl;

	if(labelPos == 1){

	}else if(labelPos == 2){
		xl = x;
	}else if(labelPos == 3){

	}else{
		xl = x + labelSize;
	}
	//Serial.print("Checking button ");Serial.println(text);
	if(lastMillis + debounceTime < millis()){
		if((p->x > xl) && (p->x < xl+w) && (p->y > y) && (p->y < y+h)){
			touched = !touched;
			eventHandler(this);
			lastMillis = millis();
			//block = true;
			//Serial.print("Button ");Serial.print(text);Serial.println(" pressed");
			return false;
		}
	}
	// if block is true return false, so canvas will not continue to
	// process the event.
	return !block;
}

/*
 * This is the update() method.
 */
void Button::update(){
	//drawBackground(bgColor);
	drawText();
	drawBorder();
}

/*
 * This method is called by the canvas and passes a pointer to it.
 * The button class uses this pointer to get a pointer to the
 * touched point, if any, and calls the checkTouch routine to detect
 * if the button was touched.
 */
/*void Button::update(Canvas* c){
	checkTouch(c->touchedPoint);
}*/
<|endoftext|>


<commit_before>#include "Astrometry.h"

#include "Maths/PDEMaths.h"
#include "Maths/PDEMatrix.h"
#include "Maths/DPVector.h"

namespace PDE
{

Vector3 RADecToDirection( const double dRA, const double dDeclination )
{
    const Vector3 xEquatorial(
        static_cast< float >( PDE::Cos( dRA ) * PDE::Cos( dDeclination ) ),
        static_cast< float >( PDE::Sin( dRA ) * PDE::Cos( dDeclination ) ),
        static_cast< float >( PDE::Sin( dDeclination ) ) );

    // rotate it by the obliquity of the ecliptic at J2000.0...
    static const float kfObliquity = PDE::Deg2Rad( 23.4392794f ); // 4444444444....
    return Matrix4::RotateAxisAngle( Vector3::Left, xEquatorial, kfObliquity );
}

}
<commit_msg>fix ra dec to ecliptic coordinate conversion<commit_after>#include "Astrometry.h"

#include "Maths/PDEMaths.h"
#include "Maths/PDEMatrix.h"
#include "Maths/DPVector.h"

namespace PDE
{

Vector3 RADecToDirection( const double dRA, const double dDeclination )
{
    const Vector3 xEquatorial(
        static_cast< float >( PDE::Cos( dRA ) * PDE::Cos( dDeclination ) ),
        static_cast< float >( PDE::Sin( dRA ) * PDE::Cos( dDeclination ) ),
        static_cast< float >( PDE::Sin( dDeclination ) ) );

    // rotate it by the obliquity of the ecliptic at J2000.0...
    static const float kfObliquity = PDE::Deg2Rad( 23.4392794f ); // 4444444444....
    return Matrix4::RotateAxisAngle( xEquatorial, Vector3::Left, kfObliquity );
}

}
<|endoftext|>


<commit_before>#include <MifareUltralight.h>

#define ULTRALIGHT_PAGE_SIZE 4
#define ULTRALIGHT_READ_SIZE 4 // we should be able to read 16 bytes at a time

#define ULTRALIGHT_DATA_START_PAGE 4
#define ULTRALIGHT_MESSAGE_LENGTH_INDEX 1
#define ULTRALIGHT_DATA_START_INDEX 2
#define ULTRALIGHT_MAX_PAGE 63

#define NFC_FORUM_TAG_TYPE_2 ("NFC Forum Type 2")

MifareUltralight::MifareUltralight(Adafruit_NFCShield_I2C& nfcShield)
{
  nfc = &nfcShield;
  ndefStartIndex = 0;
  messageLength = 0;
}

MifareUltralight::~MifareUltralight()
{
}

NfcTag MifareUltralight::read(uint8_t * uid, int uidLength)
{
  if (isUnformatted())
  {
    // TODO message needs to return a tag
    Serial.println("WARNING: Tag is not formatted.");
    return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2);
  }

  readCapabilityContainer(); // meta info for tag
  findNdefMessage();
  calculateBufferSize();

  if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE
    NdefMessage message = NdefMessage();
    message.addEmptyRecord();
    return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, message);
  }

  boolean success;
  uint8_t page;
  uint8_t index = 0;
  byte buffer[bufferSize];
  for (page = ULTRALIGHT_DATA_START_PAGE; page < ULTRALIGHT_MAX_PAGE; page++)
  {
    // read the data
    success = nfc->mifareultralight_ReadPage(page, &buffer[index]);
    if (success)
    {
      Serial.print("Page ");Serial.print(page);Serial.print(" ");
      nfc->PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE);
    }
    else
    {
      Serial.print("Read failed ");Serial.println(page);
      // TODO error handling
      messageLength = 0;
      break;
    }

    if (index > messageLength)
    {
      break;
    }

    index += ULTRALIGHT_PAGE_SIZE;

  }

  NdefMessage ndefMessage = NdefMessage(&buffer[ndefStartIndex], messageLength);
  NfcTag tag = NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, ndefMessage);
  return tag;
}

boolean MifareUltralight::isUnformatted()
{
  uint8_t page = 4;
  byte data[ULTRALIGHT_READ_SIZE];
  boolean success = nfc->mifareultralight_ReadPage (page, data);
  if (success)
  {
    return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF);
  }
  else
  {
    Serial.print("Error. Failed read page ");Serial.println(page);
    return false;
  }
}

// page 3 has tag capabilities
void MifareUltralight::readCapabilityContainer()
{
  byte data[ULTRALIGHT_PAGE_SIZE];
  int success = nfc->mifareultralight_ReadPage (3, data);
  if (success)
  {
    // See AN1303 - different rules for Mifare Family byte2 = (additional data + 48)/8
    tagCapacity = data[2] * 8;
    Serial.print("Tag capacity ");Serial.print(tagCapacity);Serial.println(" bytes");

    // TODO future versions should get lock information
  }
}

// read enough of the message to find the ndef message length
void MifareUltralight::findNdefMessage()
{
  int page;
  byte data[12]; // 3 pages
  byte* data_ptr = &data[0];

  // the nxp read command reads 4 pages, unfortunately adafruit give me one page at a time
  boolean success = true;
  for (page = 4; page < 6; page++)
  {
    success = success && nfc->mifareultralight_ReadPage(page, data_ptr);
    Serial.print("Page ");Serial.print(page);Serial.print(" - ");
    nfc->PrintHexChar(data_ptr, 4);
    data_ptr += ULTRALIGHT_PAGE_SIZE;
  }

  if (success)
  {
    if (data[0] == 0x03)
    {
      messageLength = data[1];
      ndefStartIndex = 2;
    }
    else if (data[5] == 0x3) // page 5 byte 1
    {
      // TODO should really read the lock control TLV to ensure byte[5] is correct
      messageLength = data[6];
      ndefStartIndex = 7;
    }
  }

  Serial.print("messageLength ");Serial.println(messageLength);
  Serial.print("ndefStartIndex ");Serial.println(ndefStartIndex);

}

// buffer is larger than the message, need to handle some data before and after
// message and need to ensure we read full pages
void MifareUltralight::calculateBufferSize()
{
  // TLV terminator 0xFE is 1 byte
  bufferSize = messageLength + ndefStartIndex + 1;

  if (bufferSize % ULTRALIGHT_READ_SIZE != 0)
  {
      bufferSize = ((messageLength / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE;
  }
}
<commit_msg>return NfcTag without assigning to variable. Stops code from hanging after 1 scan. O_o<commit_after>#include <MifareUltralight.h>

#define ULTRALIGHT_PAGE_SIZE 4
#define ULTRALIGHT_READ_SIZE 4 // we should be able to read 16 bytes at a time

#define ULTRALIGHT_DATA_START_PAGE 4
#define ULTRALIGHT_MESSAGE_LENGTH_INDEX 1
#define ULTRALIGHT_DATA_START_INDEX 2
#define ULTRALIGHT_MAX_PAGE 63

#define NFC_FORUM_TAG_TYPE_2 ("NFC Forum Type 2")

MifareUltralight::MifareUltralight(Adafruit_NFCShield_I2C& nfcShield)
{
  nfc = &nfcShield;
  ndefStartIndex = 0;
  messageLength = 0;
}

MifareUltralight::~MifareUltralight()
{
}

NfcTag MifareUltralight::read(uint8_t * uid, int uidLength)
{
  if (isUnformatted())
  {
    // TODO message needs to return a tag
    Serial.println("WARNING: Tag is not formatted.");
    return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2);
  }

  readCapabilityContainer(); // meta info for tag
  findNdefMessage();
  calculateBufferSize();

  if (messageLength == 0) { // data is 0x44 0x03 0x00 0xFE
    NdefMessage message = NdefMessage();
    message.addEmptyRecord();
    return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, message);
  }

  boolean success;
  uint8_t page;
  uint8_t index = 0;
  byte buffer[bufferSize];
  for (page = ULTRALIGHT_DATA_START_PAGE; page < ULTRALIGHT_MAX_PAGE; page++)
  {
    // read the data
    success = nfc->mifareultralight_ReadPage(page, &buffer[index]);
    if (success)
    {
      Serial.print("Page ");Serial.print(page);Serial.print(" ");
      nfc->PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE);
    }
    else
    {
      Serial.print("Read failed ");Serial.println(page);
      // TODO error handling
      messageLength = 0;
      break;
    }

    if (index > messageLength)
    {
      break;
    }

    index += ULTRALIGHT_PAGE_SIZE;

  }

  NdefMessage ndefMessage = NdefMessage(&buffer[ndefStartIndex], messageLength);
  return NfcTag(uid, uidLength, NFC_FORUM_TAG_TYPE_2, ndefMessage);

}

boolean MifareUltralight::isUnformatted()
{
  uint8_t page = 4;
  byte data[ULTRALIGHT_READ_SIZE];
  boolean success = nfc->mifareultralight_ReadPage (page, data);
  if (success)
  {
    return (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF);
  }
  else
  {
    Serial.print("Error. Failed read page ");Serial.println(page);
    return false;
  }
}

// page 3 has tag capabilities
void MifareUltralight::readCapabilityContainer()
{
  byte data[ULTRALIGHT_PAGE_SIZE];
  int success = nfc->mifareultralight_ReadPage (3, data);
  if (success)
  {
    // See AN1303 - different rules for Mifare Family byte2 = (additional data + 48)/8
    tagCapacity = data[2] * 8;
    Serial.print("Tag capacity ");Serial.print(tagCapacity);Serial.println(" bytes");

    // TODO future versions should get lock information
  }
}

// read enough of the message to find the ndef message length
void MifareUltralight::findNdefMessage()
{
  int page;
  byte data[12]; // 3 pages
  byte* data_ptr = &data[0];

  // the nxp read command reads 4 pages, unfortunately adafruit give me one page at a time
  boolean success = true;
  for (page = 4; page < 6; page++)
  {
    success = success && nfc->mifareultralight_ReadPage(page, data_ptr);
    Serial.print("Page ");Serial.print(page);Serial.print(" - ");
    nfc->PrintHexChar(data_ptr, 4);
    data_ptr += ULTRALIGHT_PAGE_SIZE;
  }

  if (success)
  {
    if (data[0] == 0x03)
    {
      messageLength = data[1];
      ndefStartIndex = 2;
    }
    else if (data[5] == 0x3) // page 5 byte 1
    {
      // TODO should really read the lock control TLV to ensure byte[5] is correct
      messageLength = data[6];
      ndefStartIndex = 7;
    }
  }

  Serial.print("messageLength ");Serial.println(messageLength);
  Serial.print("ndefStartIndex ");Serial.println(ndefStartIndex);

}

// buffer is larger than the message, need to handle some data before and after
// message and need to ensure we read full pages
void MifareUltralight::calculateBufferSize()
{
  // TLV terminator 0xFE is 1 byte
  bufferSize = messageLength + ndefStartIndex + 1;

  if (bufferSize % ULTRALIGHT_READ_SIZE != 0)
  {
      bufferSize = ((messageLength / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE;
  }
}
<|endoftext|>


<commit_before>//
// Created by Dennis Goldfarb on 1/3/17.
//

#include <iostream>
#include <fstream>
#include <random>

#include <OpenMS/CHEMISTRY/Element.h>
#include <OpenMS/CHEMISTRY/AASequence.h>
#include <OpenMS/CHEMISTRY/ResidueDB.h>
#include <OpenMS/CHEMISTRY/ElementDB.h>

#include "FASTAParser.h"

static const ElementDB* elementDB = ElementDB::getInstance();
static const OpenMS::ResidueDB* residueDB = OpenMS::ResidueDB::getInstance();

static std::string AMINO_ACIDS = "ADEFGHIKLNPQRSTVWYCM";
static std::string AMINO_ACIDS_NO_SULFUR = "ADEFGHIKLNPQRSTVWY";
static std::string AMINO_ACIDS_SULFUR = "CM";

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis_AA(0, AMINO_ACIDS.length()-1);
std::uniform_int_distribution<> dis_S(0, AMINO_ACIDS_SULFUR.length()-1);

std::ofstream* openOutputFiles(std::string base_path, int max_depth)
{
    // create all output files and write header to each
    std::ofstream* outfiles = new std::ofstream[max_depth];
    for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
    {
        std::string filename = "Precursor" + std::to_string(precursor_isotope) + ".tab";

        outfiles[precursor_isotope].open(base_path + filename);
        outfiles[precursor_isotope] << "probability" << "\tprecursor.mass" << std::endl;
    }

    return outfiles;
}

void closeOutputFiles(std::ofstream* outfiles, int max_depth)
{
    // close all output files
    for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
    {
        outfiles[precursor_isotope].close();
    }
    delete[] outfiles;
}

void write_distribution(const OpenMS::AASequence &p, std::ofstream* outfiles, int max_depth, bool mono)
{
    OpenMS::EmpiricalFormula precursor_ef = p.getFormula();
    OpenMS::IsotopeDistribution precursor_id = precursor_ef.getIsotopeDistribution(0);

    for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
    {
        double mass = mono ? precursor_ef.getMonoWeight() : precursor_ef.getAverageWeight();

        outfiles[precursor_isotope] << precursor_id.getContainer()[precursor_isotope].second << "\t" << mass << std::endl;
    }
}

void proteome_isotopic_distributions(std::string base_path, std::string fasta_path, float max_mass, int num_sulfurs, int max_depth, bool mono)
{
    std::ofstream* outfiles = openOutputFiles(base_path, max_depth);

    FASTAParser parser(fasta_path, max_mass, 1, 100);
    for (auto itr = parser.begin(); itr != parser.end(); ++itr)
    {
        if (num_sulfurs < 0 || itr->getFormula().getNumberOf(elementDB->getElement("Sulfur")) == num_sulfurs)
        {
            write_distribution(*itr, outfiles, max_depth, mono);
        }
    }

    closeOutputFiles(outfiles, max_depth);
}

OpenMS::AASequence create_random_peptide_sequence(int peptide_length, int num_sulfurs)
{
    OpenMS::AASequence random_peptide;

    if (num_sulfurs < 0)
    {
        for (int aa_index = 0; aa_index < peptide_length; ++aa_index)
        {
            random_peptide += residueDB->getResidue(AMINO_ACIDS[dis_AA(gen)]);
        }
    }
    else
    {
        // for insertion of sulfur containing amino acids
        for (int i = 0; i < num_sulfurs; ++i)
        {
            random_peptide += residueDB->getResidue(AMINO_ACIDS_SULFUR[dis_S(gen)]);
        }

        // random amino acid insertion (non Sulfur and Selenium amino acids)
        for (int aa_index = 0; aa_index < peptide_length; ++aa_index)
        {
            random_peptide += residueDB->getResidue(AMINO_ACIDS_NO_SULFUR[dis_AA(gen)]);
        }
    }

    return random_peptide;
}

void sample_isotopic_distributions(std::string base_path, float max_mass, int num_sulfurs, int max_depth, bool mono)
{
    std::ofstream* outfiles = openOutputFiles(base_path, max_depth);

    int max_length = max_mass/100;

    for (int peptide_length = 0; peptide_length <= max_length; ++peptide_length)
    {
        for (int sample = 0; sample < 100; ++sample)
        {
            OpenMS::AASequence random_sequence = create_random_peptide_sequence(peptide_length, num_sulfurs);

            if (random_sequence.size() > 0 && random_sequence.getMonoWeight() <= max_mass)
            {
                write_distribution(random_sequence, outfiles, max_depth, mono);
            }
        }
    }

    closeOutputFiles(outfiles, max_depth);
}

void usage()
{
    std::cout << "GenerateTrainingData fasta_path out_path max_mass num_samples S max_depth mono" << std::endl;
    std::cout << "fasta_path: The path to the fasta file to train the splines on." << std::endl;
    std::cout << "out_path: The path to the directory that will store the training data, e.g. ~/data/" << std::endl;
    std::cout << "max_mass: maximum mass allowed for sampled peptides, e.g. 8500" << std::endl;
    std::cout << "S: number of sulfurs that should be in the fragment ion. Use -1 for all (e.g. 0,1,2..)" << std::endl;
    std::cout << "max_depth: The number of isotopes to generate training data for, e.g. 3 = M0,M1,M2" << std::endl;
    std::cout << "mono: should monoisotopic masses be used or average? 1=mono, 0=average" << std::endl;
    std::cout << std::endl;
}

int main(int argc, const char ** argv)
{
    if (argc != 7)
    {
        usage();
        return 0;
    }

    std::string fasta_path = argv[1];
    std::string out_path = argv[2];
    float max_mass = atof(argv[3]);
    int S = atoi(argv[4]);
    int max_depth = atoi(argv[5]);
    bool mono = strncmp(argv[6], "1", 1) == 0 ? true : false;

    //proteome_isotopic_distributions(out_path, fasta_path, max_mass, S, max_depth, mono);
    sample_isotopic_distributions(out_path, max_mass, S, max_depth, mono);

    return 0;
}<commit_msg>put back option to sample random sequences so we can create splines for peptides of arbitrary size<commit_after>//
// Created by Dennis Goldfarb on 1/3/17.
//

#include <iostream>
#include <fstream>
#include <random>

#include <OpenMS/CHEMISTRY/Element.h>
#include <OpenMS/CHEMISTRY/AASequence.h>
#include <OpenMS/CHEMISTRY/ResidueDB.h>
#include <OpenMS/CHEMISTRY/ElementDB.h>

#include "FASTAParser.h"

static const ElementDB* elementDB = ElementDB::getInstance();
static const OpenMS::ResidueDB* residueDB = OpenMS::ResidueDB::getInstance();

static std::string AMINO_ACIDS = "ADEFGHIKLNPQRSTVWYCM";
static std::string AMINO_ACIDS_NO_SULFUR = "ADEFGHIKLNPQRSTVWY";
static std::string AMINO_ACIDS_SULFUR = "CM";

std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis_AA(0, AMINO_ACIDS.length()-1);
std::uniform_int_distribution<> dis_S(0, AMINO_ACIDS_SULFUR.length()-1);

std::ofstream* openOutputFiles(std::string base_path, int max_depth)
{
    // create all output files and write header to each
    std::ofstream* outfiles = new std::ofstream[max_depth];
    for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
    {
        std::string filename = "Precursor" + std::to_string(precursor_isotope) + ".tab";

        outfiles[precursor_isotope].open(base_path + filename);
        outfiles[precursor_isotope] << "probability" << "\tprecursor.mass" << std::endl;
    }

    return outfiles;
}

void closeOutputFiles(std::ofstream* outfiles, int max_depth)
{
    // close all output files
    for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
    {
        outfiles[precursor_isotope].close();
    }
    delete[] outfiles;
}

void write_distribution(const OpenMS::AASequence &p, std::ofstream* outfiles, int max_depth, bool mono)
{
    OpenMS::EmpiricalFormula precursor_ef = p.getFormula();
    OpenMS::IsotopeDistribution precursor_id = precursor_ef.getIsotopeDistribution(0);

    for (int precursor_isotope = 0; precursor_isotope < max_depth; ++precursor_isotope)
    {
        double mass = mono ? precursor_ef.getMonoWeight() : precursor_ef.getAverageWeight();

        outfiles[precursor_isotope] << precursor_id.getContainer()[precursor_isotope].second << "\t" << mass << std::endl;
    }
}

void proteome_isotopic_distributions(std::string base_path, std::string fasta_path, float max_mass, int num_sulfurs, int max_depth, bool mono)
{
    std::ofstream* outfiles = openOutputFiles(base_path, max_depth);

    FASTAParser parser(fasta_path, max_mass, 1, 100);
    for (auto itr = parser.begin(); itr != parser.end(); ++itr)
    {
        if (num_sulfurs < 0 || itr->getFormula().getNumberOf(elementDB->getElement("Sulfur")) == num_sulfurs)
        {
            write_distribution(*itr, outfiles, max_depth, mono);
        }
    }

    closeOutputFiles(outfiles, max_depth);
}

OpenMS::AASequence create_random_peptide_sequence(int peptide_length, int num_sulfurs)
{
    OpenMS::AASequence random_peptide;

    if (num_sulfurs < 0)
    {
        for (int aa_index = 0; aa_index < peptide_length; ++aa_index)
        {
            random_peptide += residueDB->getResidue(AMINO_ACIDS[dis_AA(gen)]);
        }
    }
    else
    {
        // for insertion of sulfur containing amino acids
        for (int i = 0; i < num_sulfurs; ++i)
        {
            random_peptide += residueDB->getResidue(AMINO_ACIDS_SULFUR[dis_S(gen)]);
        }

        // random amino acid insertion (non Sulfur and Selenium amino acids)
        for (int aa_index = 0; aa_index < peptide_length; ++aa_index)
        {
            random_peptide += residueDB->getResidue(AMINO_ACIDS_NO_SULFUR[dis_AA(gen)]);
        }
    }

    return random_peptide;
}

void sample_isotopic_distributions(std::string base_path, float max_mass, int num_sulfurs, int max_depth, bool mono)
{
    std::ofstream* outfiles = openOutputFiles(base_path, max_depth);

    int max_length = max_mass/100;

    std::cout << max_length << "\t" << max_mass << std::endl;

    for (int peptide_length = 0; peptide_length <= max_length; ++peptide_length)
    {
        for (int sample = 0; sample < 100; ++sample)
        {
            OpenMS::AASequence random_sequence = create_random_peptide_sequence(peptide_length, num_sulfurs);

            if (random_sequence.size() > 0 && random_sequence.getMonoWeight() <= max_mass)
            {
                write_distribution(random_sequence, outfiles, max_depth, mono);
            }
        }
    }

    closeOutputFiles(outfiles, max_depth);
}

void usage()
{
    std::cout << "GenerateTrainingData fasta_path out_path max_mass num_samples S max_depth mono" << std::endl;
    std::cout << "fasta_path: The path to the fasta file to train the splines on." << std::endl;
    std::cout << "out_path: The path to the directory that will store the training data, e.g. ~/data/" << std::endl;
    std::cout << "max_mass: maximum mass allowed for sampled peptides, e.g. 8500" << std::endl;
    std::cout << "S: number of sulfurs that should be in the fragment ion. Use -1 for all (e.g. 0,1,2..)" << std::endl;
    std::cout << "max_depth: The number of isotopes to generate training data for, e.g. 3 = M0,M1,M2" << std::endl;
    std::cout << "mono: should monoisotopic masses be used or average? 1=mono, 0=average" << std::endl;
    std::cout << std::endl;
}

int main(int argc, const char ** argv)
{
    if (argc != 7)
    {
        usage();
        return 0;
    }

    std::string fasta_path = argv[1];
    std::string out_path = argv[2];
    float max_mass = atof(argv[3]);
    int S = atoi(argv[4]);
    int max_depth = atoi(argv[5]);
    bool mono = strncmp(argv[6], "1", 1) == 0 ? true : false;

    //proteome_isotopic_distributions(out_path, fasta_path, max_mass, S, max_depth, mono);
    sample_isotopic_distributions(out_path, max_mass, S, max_depth, mono);

    return 0;
}<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkWarpLens.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

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

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

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

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 AUTHORS 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 "vtkWarpLens.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkWarpLens* vtkWarpLens::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkWarpLens");
  if(ret)
    {
    return (vtkWarpLens*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkWarpLens;
}

//
// Preserve old Kappa instance variable. It appears to be the
// second order symmetric radial lens distortion parameter
//
void vtkWarpLens::SetKappa(float kappa)
{
  this->SetK1(kappa);
}

float vtkWarpLens::GetKappa()
{
  return this->GetK1();
}

//
// Preserve old Center point instance variable.
// It appears to be the center of radial distortion in pixel coordinates
//
void vtkWarpLens::SetCenter(float centerX, float centerY)
{
  this->SetPrincipalPoint(centerX, centerY);
}

float *vtkWarpLens::GetCenter()
{
  return this->GetPrincipalPoint();
}

vtkWarpLens::vtkWarpLens()
{
  this->PrincipalPoint[0] = 0.0;
  this->PrincipalPoint[1] = 0.0;
  this->K1 = -1.0e-6;
  this->K2 = 0.0;
  this->P1 = 0.0;
  this->P2 = 0.0;
  this->FormatWidth = 1.0;
  this->FormatHeight = 1.0;
  this->ImageWidth = 1;
  this->ImageHeight = 1;
}

void vtkWarpLens::Execute()
{
  vtkPoints *inPts;
  vtkPoints *newPts;
  vtkIdType ptId, numPts;
  float *pixel, newPixel[3];
  vtkPointSet *input = this->GetInput();
  vtkPointSet *output = this->GetOutput();
  float x;
  float y;
  float newX;
  float newY;
  float rSquared;

  vtkDebugMacro(<<"Warping data to a point");

  // First, copy the input to the output as a starting point
  output->CopyStructure( input );

  inPts = input->GetPoints();
  if (!inPts )
    {
    vtkErrorMacro(<<"No input data");
    return;
    }

  numPts = inPts->GetNumberOfPoints();
  newPts = vtkPoints::New();
  newPts->SetNumberOfPoints(numPts);

  //
  // Loop over all pixels, adjusting locations
  //
  for (ptId=0; ptId < numPts; ptId++)
    {
    pixel = inPts->GetPoint(ptId);

    //
    // Convert to working in mm from pixels and make the Principal Point (0,0)
    //
    x = pixel[0] / this->ImageWidth * this->FormatWidth -
      this->PrincipalPoint[0];
    y = (- pixel[1]) / this->ImageHeight * this->FormatHeight +
      this->PrincipalPoint[1];

    //
    // Lens distortion causes a point's image on the imaging surface to
    // shifted from its true position as if it had been imaged by an ideal pin-
    // hole camera.
    //
    // The corrected location adds the correction for radial len distortion
    // and for the decentering lens distortion
    //
    rSquared = pow(x,2) + pow(y,2);

    newX = x * (1 + this->K1 * rSquared + this->K2 * pow(rSquared,2) ) +
      this->P1 * (rSquared + 2 * pow(x,2)) + 2 * this->P2 * x * y;

    newY = y * (1 + this->K1 * rSquared + this->K2 * pow(rSquared,2) ) +
      this->P2 * (rSquared + 2 * pow(y,2)) + 2 * this->P1 * x * y;

    //
    // Convert back to pixels
    //
    newPixel[0] = (newX + this->PrincipalPoint[0]) / this->FormatWidth *
      this->ImageWidth;
    newPixel[1] = (newY - this->PrincipalPoint[1]) /
      this->FormatHeight * this->ImageHeight * -1;

    newPixel[2] = pixel[2];             // pixel color
    newPts->SetPoint(ptId, newPixel);
    }

  //
  // Update ourselves and release memory
  //
  output->GetPointData()->CopyNormalsOff(); // distorted geometry
  output->GetPointData()->PassData(input->GetPointData());

  output->SetPoints(newPts);
  newPts->Delete();
}

void vtkWarpLens::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkPointSetToPointSetFilter::PrintSelf(os,indent);

  os << indent << "PrincipalPoint: (" << this->PrincipalPoint[0] << ", "
    << this->PrincipalPoint[1] << ") in mm\n";
  os << indent << "K1: " << this->K1 << "\n";
  os << indent << "K2: " << this->K2 << "\n";
  os << indent << "P1: " << this->P1 << "\n";
  os << indent << "P2: " << this->P2 << "\n";
  os << indent << "FormatWidth: " << this->FormatWidth << " in mm\n";
  os << indent << "FormatHeight: " << this->FormatHeight << " in mm\n";
  os << indent << "ImageWidth: " << this->ImageWidth << " in pixels\n";
  os << indent << "ImageHeight: " << this->ImageHeight << " in pixels\n";
}
<commit_msg>removed use of pow2<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkWarpLens.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

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

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

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

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

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 AUTHORS 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 "vtkWarpLens.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"

//----------------------------------------------------------------------------
vtkWarpLens* vtkWarpLens::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkWarpLens");
  if(ret)
    {
    return (vtkWarpLens*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkWarpLens;
}

//
// Preserve old Kappa instance variable. It appears to be the
// second order symmetric radial lens distortion parameter
//
void vtkWarpLens::SetKappa(float kappa)
{
  this->SetK1(kappa);
}

float vtkWarpLens::GetKappa()
{
  return this->GetK1();
}

//
// Preserve old Center point instance variable.
// It appears to be the center of radial distortion in pixel coordinates
//
void vtkWarpLens::SetCenter(float centerX, float centerY)
{
  this->SetPrincipalPoint(centerX, centerY);
}

float *vtkWarpLens::GetCenter()
{
  return this->GetPrincipalPoint();
}

vtkWarpLens::vtkWarpLens()
{
  this->PrincipalPoint[0] = 0.0;
  this->PrincipalPoint[1] = 0.0;
  this->K1 = -1.0e-6;
  this->K2 = 0.0;
  this->P1 = 0.0;
  this->P2 = 0.0;
  this->FormatWidth = 1.0;
  this->FormatHeight = 1.0;
  this->ImageWidth = 1;
  this->ImageHeight = 1;
}

void vtkWarpLens::Execute()
{
  vtkPoints *inPts;
  vtkPoints *newPts;
  vtkIdType ptId, numPts;
  float *pixel, newPixel[3];
  vtkPointSet *input = this->GetInput();
  vtkPointSet *output = this->GetOutput();
  float x;
  float y;
  float newX;
  float newY;
  float rSquared;

  vtkDebugMacro(<<"Warping data to a point");

  // First, copy the input to the output as a starting point
  output->CopyStructure( input );

  inPts = input->GetPoints();
  if (!inPts )
    {
    vtkErrorMacro(<<"No input data");
    return;
    }

  numPts = inPts->GetNumberOfPoints();
  newPts = vtkPoints::New();
  newPts->SetNumberOfPoints(numPts);

  //
  // Loop over all pixels, adjusting locations
  //
  for (ptId=0; ptId < numPts; ptId++)
    {
    pixel = inPts->GetPoint(ptId);

    //
    // Convert to working in mm from pixels and make the Principal Point (0,0)
    //
    x = pixel[0] / this->ImageWidth * this->FormatWidth -
      this->PrincipalPoint[0];
    y = (- pixel[1]) / this->ImageHeight * this->FormatHeight +
      this->PrincipalPoint[1];

    //
    // Lens distortion causes a point's image on the imaging surface to
    // shifted from its true position as if it had been imaged by an ideal pin-
    // hole camera.
    //
    // The corrected location adds the correction for radial len distortion
    // and for the decentering lens distortion
    //
    rSquared = x*x + y*y;

    newX = x * (1 + this->K1 * rSquared + this->K2 * rSquared*rSquared ) +
      this->P1 * (rSquared + 2 * x*x) + 2 * this->P2 * x * y;

    newY = y * (1 + this->K1 * rSquared + this->K2 * rSquared*rSquared ) +
      this->P2 * (rSquared + 2 * y*y) + 2 * this->P1 * x * y;

    //
    // Convert back to pixels
    //
    newPixel[0] = (newX + this->PrincipalPoint[0]) / this->FormatWidth *
      this->ImageWidth;
    newPixel[1] = (newY - this->PrincipalPoint[1]) /
      this->FormatHeight * this->ImageHeight * -1;

    newPixel[2] = pixel[2];             // pixel color
    newPts->SetPoint(ptId, newPixel);
    }

  //
  // Update ourselves and release memory
  //
  output->GetPointData()->CopyNormalsOff(); // distorted geometry
  output->GetPointData()->PassData(input->GetPointData());

  output->SetPoints(newPts);
  newPts->Delete();
}

void vtkWarpLens::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkPointSetToPointSetFilter::PrintSelf(os,indent);

  os << indent << "PrincipalPoint: (" << this->PrincipalPoint[0] << ", "
    << this->PrincipalPoint[1] << ") in mm\n";
  os << indent << "K1: " << this->K1 << "\n";
  os << indent << "K2: " << this->K2 << "\n";
  os << indent << "P1: " << this->P1 << "\n";
  os << indent << "P2: " << this->P2 << "\n";
  os << indent << "FormatWidth: " << this->FormatWidth << " in mm\n";
  os << indent << "FormatHeight: " << this->FormatHeight << " in mm\n";
  os << indent << "ImageWidth: " << this->ImageWidth << " in pixels\n";
  os << indent << "ImageHeight: " << this->ImageHeight << " in pixels\n";
}
<|endoftext|>