<commit_before>// Copyright (c) 2009-2019 The Bitcoin Core developers
// Copyright (c) 2014-2019 The DigiByte Core developers
// Copyright (c) 2014-2019 The Auroracoin Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/auroracoin-config.h>
#endif

#include <fs.h>
#include <qt/intro.h>
#include <qt/forms/ui_intro.h>

#include <qt/guiconstants.h>
#include <qt/guiutil.h>

#include <interfaces/node.h>
#include <util/system.h>

#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

#include <cmath>

/* Total required space (in GB) depending on user choice (prune, not prune) */
static uint64_t requiredSpace;

/* Check free space asynchronously to prevent hanging the UI thread.

   Up to one request to check a path is in flight to this thread; when the check()
   function runs, the current path is requested from the associated Intro object.
   The reply is sent back through a signal.

   This ensures that no queue of checking requests is built up while the user is
   still entering the path, and that always the most recently entered path is checked as
   soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
    Q_OBJECT

public:
    explicit FreespaceChecker(Intro *intro);

    enum Status {
        ST_OK,
        ST_ERROR
    };

public Q_SLOTS:
    void check();

Q_SIGNALS:
    void reply(int status, const QString &message, quint64 available);

private:
    Intro *intro;
};

#include <qt/intro.moc>

FreespaceChecker::FreespaceChecker(Intro *_intro)
{
    this->intro = _intro;
}

void FreespaceChecker::check()
{
    QString dataDirStr = intro->getPathToCheck();
    fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr);
    uint64_t freeBytesAvailable = 0;
    int replyStatus = ST_OK;
    QString replyMessage = tr("A new data directory will be created.");

    /* Find first parent that exists, so that fs::space does not fail */
    fs::path parentDir = dataDir;
    fs::path parentDirOld = fs::path();
    while(parentDir.has_parent_path() && !fs::exists(parentDir))
    {
        parentDir = parentDir.parent_path();

        /* Check if we make any progress, break if not to prevent an infinite loop here */
        if (parentDirOld == parentDir)
            break;

        parentDirOld = parentDir;
    }

    try {
        freeBytesAvailable = fs::space(parentDir).available;
        if(fs::exists(dataDir))
        {
            if(fs::is_directory(dataDir))
            {
                QString separator = "" + QDir::toNativeSeparators("/") + tr("name") + "";
                replyStatus = ST_OK;
                replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
            } else {
                replyStatus = ST_ERROR;
                replyMessage = tr("Path already exists, and is not a directory.");
            }
        }
    } catch (const fs::filesystem_error&)
    {
        /* Parent directory does not exist or is not accessible */
        replyStatus = ST_ERROR;
        replyMessage = tr("Cannot create data directory here.");
    }
    Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}

Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_size) :
    QDialog(parent),
    ui(new Ui::Intro),
    thread(nullptr),
    signalled(false),
    m_blockchain_size(blockchain_size),
    m_chain_state_size(chain_state_size)
{
    ui->setupUi(this);
    ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME));
    ui->storageLabel->setText(ui->storageLabel->text().arg(PACKAGE_NAME));

    ui->lblExplanation1->setText(ui->lblExplanation1->text()
        .arg(PACKAGE_NAME)
        .arg(m_blockchain_size)
        .arg(2014)
        .arg(tr("Auroracoin"))
    );
    ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME));

    uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0));
    if (pruneTarget > 1) { // -prune=1 means enabled, above that it's a size in MB
        ui->prune->setChecked(true);
        ui->prune->setEnabled(false);
    }
    ui->prune->setText(tr("Discard blocks after verification, except most recent %1 GB (prune)").arg(pruneTarget ? pruneTarget / 1000 : 2));
    requiredSpace = m_blockchain_size;
    QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time.");
    if (pruneTarget) {
        uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
        if (prunedGBs <= requiredSpace) {
            requiredSpace = prunedGBs;
            storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory.");
        }
        ui->lblExplanation3->setVisible(true);
    } else {
        ui->lblExplanation3->setVisible(false);
    }
    requiredSpace += m_chain_state_size;
    ui->sizeWarningLabel->setText(
        tr("%1 will download and store a copy of the Auroracoin block chain.").arg(PACKAGE_NAME) + " " +
        storageRequiresMsg.arg(requiredSpace) + " " +
        tr("The wallet will also be stored in this directory.")
    );
    startThread();
}

Intro::~Intro()
{
    delete ui;
    /* Ensure thread is finished before it is deleted */
    thread->quit();
    thread->wait();
}

QString Intro::getDataDirectory()
{
    return ui->dataDirectory->text();
}

void Intro::setDataDirectory(const QString &dataDir)
{
    ui->dataDirectory->setText(dataDir);
    if(dataDir == GUIUtil::getDefaultDataDirectory())
    {
        ui->dataDirDefault->setChecked(true);
        ui->dataDirectory->setEnabled(false);
        ui->ellipsisButton->setEnabled(false);
    } else {
        ui->dataDirCustom->setChecked(true);
        ui->dataDirectory->setEnabled(true);
        ui->ellipsisButton->setEnabled(true);
    }
}

bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune)
{
    did_show_intro = false;

    QSettings settings;
    /* If data directory provided on command line, no need to look at settings
       or show a picking dialog */
    if(!gArgs.GetArg("-datadir", "").empty())
        return true;
    /* 1) Default data directory for operating system */
    QString dataDir = GUIUtil::getDefaultDataDirectory();
    /* 2) Allow QSettings to override default dir */
    dataDir = settings.value("strDataDir", dataDir).toString();

    if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false))
    {
        /* Use selectParams here to guarantee Params() can be used by node interface */
        try {
            node.selectParams(gArgs.GetChainName());
        } catch (const std::exception&) {
            return false;
        }

        /* If current default data directory does not exist, let the user choose one */
        Intro intro(0, node.getAssumedBlockchainSize(), node.getAssumedChainStateSize());
        intro.setDataDirectory(dataDir);
        intro.setWindowIcon(QIcon(":icons/auroracoin"));
        did_show_intro = true;

        while(true)
        {
            if(!intro.exec())
            {
                /* Cancel clicked */
                return false;
            }
            dataDir = intro.getDataDirectory();
            try {
                if (TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir))) {
                    // If a new data directory has been created, make wallets subdirectory too
                    TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir) / "wallets");
                }
                break;
            } catch (const fs::filesystem_error&) {
                QMessageBox::critical(nullptr, PACKAGE_NAME,
                    tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
                /* fall through, back to choosing screen */
            }
        }

        // Additional preferences:
        prune = intro.ui->prune->isChecked();

        settings.setValue("strDataDir", dataDir);
        settings.setValue("fReset", false);
    }
    /* Only override -datadir if different from the default, to make it possible to
     * override -datadir in the auroracoin.conf file in the default data directory
     * (to be consistent with auroracoind behavior)
     */
    if(dataDir != GUIUtil::getDefaultDataDirectory()) {
        node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
    }
    return true;
}

void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
{
    switch(status)
    {
    case FreespaceChecker::ST_OK:
        ui->errorMessage->setText(message);
        ui->errorMessage->setStyleSheet("");
        break;
    case FreespaceChecker::ST_ERROR:
        ui->errorMessage->setText(tr("Error") + ": " + message);
        ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
        break;
    }
    /* Indicate number of bytes available */
    if(status == FreespaceChecker::ST_ERROR)
    {
        ui->freeSpace->setText("");
    } else {
        QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
        if(bytesAvailable < requiredSpace * GB_BYTES)
        {
            freeString += " " + tr("(of %n GB needed)", "", requiredSpace);
            ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
        } else {
            ui->freeSpace->setStyleSheet("");
        }
        ui->freeSpace->setText(freeString + ".");
    }
    /* Don't allow confirm in ERROR state */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
}

void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
{
    /* Disable OK button until check result comes in */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    checkPath(dataDirStr);
}

void Intro::on_ellipsisButton_clicked()
{
    QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(nullptr, "Choose data directory", ui->dataDirectory->text()));
    if(!dir.isEmpty())
        ui->dataDirectory->setText(dir);
}

void Intro::on_dataDirDefault_clicked()
{
    setDataDirectory(GUIUtil::getDefaultDataDirectory());
}

void Intro::on_dataDirCustom_clicked()
{
    ui->dataDirectory->setEnabled(true);
    ui->ellipsisButton->setEnabled(true);
}

void Intro::startThread()
{
    thread = new QThread(this);
    FreespaceChecker *executor = new FreespaceChecker(this);
    executor->moveToThread(thread);

    connect(executor, &FreespaceChecker::reply, this, &Intro::setStatus);
    connect(this, &Intro::requestCheck, executor, &FreespaceChecker::check);
    /*  make sure executor object is deleted in its own thread */
    connect(thread, &QThread::finished, executor, &QObject::deleteLater);

    thread->start();
}

void Intro::checkPath(const QString &dataDir)
{
    mutex.lock();
    pathToCheck = dataDir;
    if(!signalled)
    {
        signalled = true;
        Q_EMIT requestCheck();
    }
    mutex.unlock();
}

QString Intro::getPathToCheck()
{
    QString retval;
    mutex.lock();
    retval = pathToCheck;
    signalled = false; /* new request can be queued now */
    mutex.unlock();
    return retval;
}
<commit_msg>Bitcoin: 9924bce317b96ab0c57efb99330abd11b6f16b9a ([gui] intro: enable pruning by default unless disk is big).<commit_after>// Copyright (c) 2009-2019 The Bitcoin Core developers
// Copyright (c) 2014-2019 The DigiByte Core developers
// Copyright (c) 2014-2019 The Auroracoin Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/auroracoin-config.h>
#endif

#include <fs.h>
#include <qt/intro.h>
#include <qt/forms/ui_intro.h>

#include <qt/guiconstants.h>
#include <qt/guiutil.h>

#include <interfaces/node.h>
#include <util/system.h>

#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

#include <cmath>

/* Total required space (in GB) depending on user choice (prune, not prune) */
static uint64_t requiredSpace;

/* Check free space asynchronously to prevent hanging the UI thread.

   Up to one request to check a path is in flight to this thread; when the check()
   function runs, the current path is requested from the associated Intro object.
   The reply is sent back through a signal.

   This ensures that no queue of checking requests is built up while the user is
   still entering the path, and that always the most recently entered path is checked as
   soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
    Q_OBJECT

public:
    explicit FreespaceChecker(Intro *intro);

    enum Status {
        ST_OK,
        ST_ERROR
    };

public Q_SLOTS:
    void check();

Q_SIGNALS:
    void reply(int status, const QString &message, quint64 available);

private:
    Intro *intro;
};

#include <qt/intro.moc>

FreespaceChecker::FreespaceChecker(Intro *_intro)
{
    this->intro = _intro;
}

void FreespaceChecker::check()
{
    QString dataDirStr = intro->getPathToCheck();
    fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr);
    uint64_t freeBytesAvailable = 0;
    int replyStatus = ST_OK;
    QString replyMessage = tr("A new data directory will be created.");

    /* Find first parent that exists, so that fs::space does not fail */
    fs::path parentDir = dataDir;
    fs::path parentDirOld = fs::path();
    while(parentDir.has_parent_path() && !fs::exists(parentDir))
    {
        parentDir = parentDir.parent_path();

        /* Check if we make any progress, break if not to prevent an infinite loop here */
        if (parentDirOld == parentDir)
            break;

        parentDirOld = parentDir;
    }

    try {
        freeBytesAvailable = fs::space(parentDir).available;
        if(fs::exists(dataDir))
        {
            if(fs::is_directory(dataDir))
            {
                QString separator = "" + QDir::toNativeSeparators("/") + tr("name") + "";
                replyStatus = ST_OK;
                replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
            } else {
                replyStatus = ST_ERROR;
                replyMessage = tr("Path already exists, and is not a directory.");
            }
        }
    } catch (const fs::filesystem_error&)
    {
        /* Parent directory does not exist or is not accessible */
        replyStatus = ST_ERROR;
        replyMessage = tr("Cannot create data directory here.");
    }
    Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}

Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_size) :
    QDialog(parent),
    ui(new Ui::Intro),
    thread(nullptr),
    signalled(false),
    m_blockchain_size(blockchain_size),
    m_chain_state_size(chain_state_size)
{
    ui->setupUi(this);
    ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME));
    ui->storageLabel->setText(ui->storageLabel->text().arg(PACKAGE_NAME));

    ui->lblExplanation1->setText(ui->lblExplanation1->text()
        .arg(PACKAGE_NAME)
        .arg(m_blockchain_size)
        .arg(2014)
        .arg(tr("Auroracoin"))
    );
    ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME));

    uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0));
    if (pruneTarget > 1) { // -prune=1 means enabled, above that it's a size in MB
        ui->prune->setChecked(true);
        ui->prune->setEnabled(false);
    }
    ui->prune->setText(tr("Discard blocks after verification, except most recent %1 GB (prune)").arg(pruneTarget ? pruneTarget / 1000 : 2));
    requiredSpace = m_blockchain_size;
    QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time.");
    if (pruneTarget) {
        uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
        if (prunedGBs <= requiredSpace) {
            requiredSpace = prunedGBs;
            storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory.");
        }
        ui->lblExplanation3->setVisible(true);
    } else {
        ui->lblExplanation3->setVisible(false);
    }
    requiredSpace += m_chain_state_size;
    ui->sizeWarningLabel->setText(
        tr("%1 will download and store a copy of the Auroracoin block chain.").arg(PACKAGE_NAME) + " " +
        storageRequiresMsg.arg(requiredSpace) + " " +
        tr("The wallet will also be stored in this directory.")
    );
    startThread();
}

Intro::~Intro()
{
    delete ui;
    /* Ensure thread is finished before it is deleted */
    thread->quit();
    thread->wait();
}

QString Intro::getDataDirectory()
{
    return ui->dataDirectory->text();
}

void Intro::setDataDirectory(const QString &dataDir)
{
    ui->dataDirectory->setText(dataDir);
    if(dataDir == GUIUtil::getDefaultDataDirectory())
    {
        ui->dataDirDefault->setChecked(true);
        ui->dataDirectory->setEnabled(false);
        ui->ellipsisButton->setEnabled(false);
    } else {
        ui->dataDirCustom->setChecked(true);
        ui->dataDirectory->setEnabled(true);
        ui->ellipsisButton->setEnabled(true);
    }
}

bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune)
{
    did_show_intro = false;

    QSettings settings;
    /* If data directory provided on command line, no need to look at settings
       or show a picking dialog */
    if(!gArgs.GetArg("-datadir", "").empty())
        return true;
    /* 1) Default data directory for operating system */
    QString dataDir = GUIUtil::getDefaultDataDirectory();
    /* 2) Allow QSettings to override default dir */
    dataDir = settings.value("strDataDir", dataDir).toString();

    if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false))
    {
        /* Use selectParams here to guarantee Params() can be used by node interface */
        try {
            node.selectParams(gArgs.GetChainName());
        } catch (const std::exception&) {
            return false;
        }

        /* If current default data directory does not exist, let the user choose one */
        Intro intro(0, node.getAssumedBlockchainSize(), node.getAssumedChainStateSize());
        intro.setDataDirectory(dataDir);
        intro.setWindowIcon(QIcon(":icons/auroracoin"));
        did_show_intro = true;

        while(true)
        {
            if(!intro.exec())
            {
                /* Cancel clicked */
                return false;
            }
            dataDir = intro.getDataDirectory();
            try {
                if (TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir))) {
                    // If a new data directory has been created, make wallets subdirectory too
                    TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir) / "wallets");
                }
                break;
            } catch (const fs::filesystem_error&) {
                QMessageBox::critical(nullptr, PACKAGE_NAME,
                    tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
                /* fall through, back to choosing screen */
            }
        }

        // Additional preferences:
        prune = intro.ui->prune->isChecked();

        settings.setValue("strDataDir", dataDir);
        settings.setValue("fReset", false);
    }
    /* Only override -datadir if different from the default, to make it possible to
     * override -datadir in the auroracoin.conf file in the default data directory
     * (to be consistent with auroracoind behavior)
     */
    if(dataDir != GUIUtil::getDefaultDataDirectory()) {
        node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
    }
    return true;
}

void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
{
    switch(status)
    {
    case FreespaceChecker::ST_OK:
        ui->errorMessage->setText(message);
        ui->errorMessage->setStyleSheet("");
        break;
    case FreespaceChecker::ST_ERROR:
        ui->errorMessage->setText(tr("Error") + ": " + message);
        ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
        break;
    }
    /* Indicate number of bytes available */
    if(status == FreespaceChecker::ST_ERROR)
    {
        ui->freeSpace->setText("");
    } else {
        QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
        if(bytesAvailable < requiredSpace * GB_BYTES)
        {
            freeString += " " + tr("(of %n GB needed)", "", requiredSpace);
            ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
            ui->prune->setChecked(true);
        } else if (bytesAvailable / GB_BYTES - requiredSpace < 10) {
            freeString += " " + tr("(%n GB needed for full chain)", "", requiredSpace);
            ui->freeSpace->setStyleSheet("QLabel { color: #999900 }");
            ui->prune->setChecked(true);
        } else {
            ui->freeSpace->setStyleSheet("");
        }
        ui->freeSpace->setText(freeString + ".");
    }
    /* Don't allow confirm in ERROR state */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
}

void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
{
    /* Disable OK button until check result comes in */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    checkPath(dataDirStr);
}

void Intro::on_ellipsisButton_clicked()
{
    QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(nullptr, "Choose data directory", ui->dataDirectory->text()));
    if(!dir.isEmpty())
        ui->dataDirectory->setText(dir);
}

void Intro::on_dataDirDefault_clicked()
{
    setDataDirectory(GUIUtil::getDefaultDataDirectory());
}

void Intro::on_dataDirCustom_clicked()
{
    ui->dataDirectory->setEnabled(true);
    ui->ellipsisButton->setEnabled(true);
}

void Intro::startThread()
{
    thread = new QThread(this);
    FreespaceChecker *executor = new FreespaceChecker(this);
    executor->moveToThread(thread);

    connect(executor, &FreespaceChecker::reply, this, &Intro::setStatus);
    connect(this, &Intro::requestCheck, executor, &FreespaceChecker::check);
    /*  make sure executor object is deleted in its own thread */
    connect(thread, &QThread::finished, executor, &QObject::deleteLater);

    thread->start();
}

void Intro::checkPath(const QString &dataDir)
{
    mutex.lock();
    pathToCheck = dataDir;
    if(!signalled)
    {
        signalled = true;
        Q_EMIT requestCheck();
    }
    mutex.unlock();
}

QString Intro::getPathToCheck()
{
    QString retval;
    mutex.lock();
    retval = pathToCheck;
    signalled = false; /* new request can be queued now */
    mutex.unlock();
    return retval;
}
<|endoftext|>


<commit_before>// @(#)root/mathmore:$Id$
// Authors: L. Moneta, A. Zsenei   08/2005
 /**********************************************************************
  *                                                                    *
  * Copyright (c) 2004 moneta,  CERN/PH-SFT                            *
  *                                                                    *
  * This library is free software; you can redistribute it and/or      *
  * modify it under the terms of the GNU General Public License        *
  * as published by the Free Software Foundation; either version 2     *
  * of the License, or (at your option) any later version.             *
  *                                                                    *
  * This library is distributed in the hope that it will be useful,    *
  * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   *
  * General Public License for more details.                           *
  *                                                                    *
  * You should have received a copy of the GNU General Public License  *
  * along with this library (see file COPYING); if not, write          *
  * to the Free Software Foundation, Inc., 59 Temple Place, Suite      *
  * 330, Boston, MA 02111-1307 USA, or contact the author.             *
  *                                                                    *
  **********************************************************************/

// Implementation file for class GSLMinimizer1D
//
// Created by: moneta  at Wed Dec  1 15:04:51 2004
//
// Last update: Wed Dec  1 15:04:51 2004
//

#include <assert.h>

#include "Math/GSLMinimizer1D.h"
#include "Math/Error.h"

#include "GSLFunctionWrapper.h"
#include "GSL1DMinimizerWrapper.h"

#include "gsl/gsl_min.h"
#include "gsl/gsl_errno.h"

#include <iostream>

namespace ROOT {

namespace Math {

GSLMinimizer1D::GSLMinimizer1D(Minim1D::Type type) :
    fXmin(0), fXlow(0), fXup(0), fMin(0), fLow(0), fUp(0),
    fIter(0), fStatus(-1), fIsSet(false),
    fMinimizer(0), fFunction(0)
{
   // construct a minimizer passing the algorithm type as an enumeration

   const gsl_min_fminimizer_type* T = 0 ;
   switch ( type )
   {
   case Minim1D::kGOLDENSECTION          :
      T = gsl_min_fminimizer_goldensection;
      break ;
   case Minim1D::kBRENT       :
      T = gsl_min_fminimizer_brent;
      break ;
   default :
      // default case is brent
      T = gsl_min_fminimizer_brent;
      break ;
   }

   fMinimizer = new GSL1DMinimizerWrapper(T);
   fFunction  = new GSLFunctionWrapper();

}

GSLMinimizer1D::~GSLMinimizer1D()
{
   // destructor: clean up minimizer and function pointers

   if (fMinimizer) delete fMinimizer;
   if (fFunction)  delete  fFunction;
}

GSLMinimizer1D::GSLMinimizer1D(const GSLMinimizer1D &): IMinimizer1D()
{
   // dummy copy ctr
}

GSLMinimizer1D & GSLMinimizer1D::operator = (const GSLMinimizer1D &rhs)
{
   // dummy operator =
   if (this == &rhs) return *this;  // time saving self-test
   return *this;
}

void GSLMinimizer1D::SetFunction(  GSLFuncPointer f, void * p, double xmin, double xlow, double xup) {
   // set the function to be minimized
   assert(fFunction);
   assert(fMinimizer);
   fXlow = xlow;
   fXup = xup;
   fXmin = xmin;
   fFunction->SetFuncPointer( f );
   fFunction->SetParams( p );

#ifdef DEBUG
   std::cout << " [ "<< xlow << " , " << xup << " ]" << std::endl;
#endif

   int status = gsl_min_fminimizer_set( fMinimizer->Get(), fFunction->GetFunc(), xmin, xlow, xup);
   if (status != GSL_SUCCESS)
      std::cerr <<"GSLMinimizer1D: Error:  Interval [ "<< xlow << " , " << xup << " ] does not contain a minimum" << std::endl;

   fIsSet = true;
   fStatus = -1;
   return;
}

int GSLMinimizer1D::Iterate() {
   // perform an iteration and update values
   if (!fIsSet) {
      std::cerr << "GSLMinimizer1D- Error: Function has not been set in Minimizer" << std::endl;
      return -1;
   }

   int status =  gsl_min_fminimizer_iterate(fMinimizer->Get());
   // update values
   fXmin = gsl_min_fminimizer_x_minimum(fMinimizer->Get() );
   fMin = gsl_min_fminimizer_f_minimum(fMinimizer->Get() );
   // update interval values
   fXlow =  gsl_min_fminimizer_x_lower(fMinimizer->Get() );
   fXup =  gsl_min_fminimizer_x_upper(fMinimizer->Get() );
   fLow =  gsl_min_fminimizer_f_lower(fMinimizer->Get() );
   fUp =  gsl_min_fminimizer_f_upper(fMinimizer->Get() );
   return status;
}

double GSLMinimizer1D::XMinimum() const {
   // return x value at function minimum
   return fXmin;
}

double GSLMinimizer1D::XLower() const {
   // return lower x value of bracketing interval
   return fXlow;
}

double GSLMinimizer1D::XUpper() const {
   // return upper x value of bracketing interval
   return fXup;
}

double GSLMinimizer1D::FValMinimum() const {
   // return function value at minimum
   return fMin;
}

double GSLMinimizer1D::FValLower() const {
   // return function value at x lower
   return fLow;
}

double GSLMinimizer1D::FValUpper() const {
   // return function value at x upper
   return fUp;
}

const char * GSLMinimizer1D::Name() const {
   // return name of minimization algorithm
   return gsl_min_fminimizer_name(fMinimizer->Get() );
}

bool GSLMinimizer1D::Minimize (int maxIter, double absTol, double relTol)
{
   // find the minimum via multiple iterations
   fStatus = -1;
   int iter = 0;
   int status = 0;
   do {
      iter++;
      status = Iterate();
      if (status != GSL_SUCCESS) {
         MATH_ERROR_MSG("GSLMinimizer1D::Minimize","error returned when performing an iteration");
         fStatus = status;
         return false;
      }

#ifdef DEBUG
      std::cout << "Min1D - iteration " << iter << " interval : [ " << fXlow << "  , " << fXup << " ]  min = " << fXmin
                << " fmin " << fMin << " f(a) " << fLow << " f(b) " << fUp << std::endl;
#endif

      status =  TestInterval(fXlow, fXup, absTol, relTol);
      if (status == GSL_SUCCESS) {
         fIter = iter;
         fStatus = status;
         return true;
      }
   }
   while (status == GSL_CONTINUE && iter < maxIter);
   if (status == GSL_CONTINUE) {
      double tol = std::abs(fXup-fXlow);
      MATH_INFO_MSGVAL("GSLMinimizer1D::Minimize","exceeded max iterations, reached tolerance is not sufficient",tol);
   }
   fStatus = status;
   return false;
}

int GSLMinimizer1D::TestInterval( double xlow, double xup, double epsAbs, double epsRel) {
// static function to test interval
   return gsl_min_test_interval(xlow, xup, epsAbs, epsRel);
}

} // end namespace Math

} // end namespace ROOT

<commit_msg>add missing include to cmath<commit_after>// @(#)root/mathmore:$Id$
// Authors: L. Moneta, A. Zsenei   08/2005
 /**********************************************************************
  *                                                                    *
  * Copyright (c) 2004 moneta,  CERN/PH-SFT                            *
  *                                                                    *
  * This library is free software; you can redistribute it and/or      *
  * modify it under the terms of the GNU General Public License        *
  * as published by the Free Software Foundation; either version 2     *
  * of the License, or (at your option) any later version.             *
  *                                                                    *
  * This library is distributed in the hope that it will be useful,    *
  * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   *
  * General Public License for more details.                           *
  *                                                                    *
  * You should have received a copy of the GNU General Public License  *
  * along with this library (see file COPYING); if not, write          *
  * to the Free Software Foundation, Inc., 59 Temple Place, Suite      *
  * 330, Boston, MA 02111-1307 USA, or contact the author.             *
  *                                                                    *
  **********************************************************************/

// Implementation file for class GSLMinimizer1D
//
// Created by: moneta  at Wed Dec  1 15:04:51 2004
//
// Last update: Wed Dec  1 15:04:51 2004
//

#include <assert.h>

#include "Math/GSLMinimizer1D.h"
#include "Math/Error.h"

#include "GSLFunctionWrapper.h"
#include "GSL1DMinimizerWrapper.h"

#include "gsl/gsl_min.h"
#include "gsl/gsl_errno.h"

#include <iostream>
#include <cmath>

namespace ROOT {

namespace Math {

GSLMinimizer1D::GSLMinimizer1D(Minim1D::Type type) :
    fXmin(0), fXlow(0), fXup(0), fMin(0), fLow(0), fUp(0),
    fIter(0), fStatus(-1), fIsSet(false),
    fMinimizer(0), fFunction(0)
{
   // construct a minimizer passing the algorithm type as an enumeration

   const gsl_min_fminimizer_type* T = 0 ;
   switch ( type )
   {
   case Minim1D::kGOLDENSECTION          :
      T = gsl_min_fminimizer_goldensection;
      break ;
   case Minim1D::kBRENT       :
      T = gsl_min_fminimizer_brent;
      break ;
   default :
      // default case is brent
      T = gsl_min_fminimizer_brent;
      break ;
   }

   fMinimizer = new GSL1DMinimizerWrapper(T);
   fFunction  = new GSLFunctionWrapper();

}

GSLMinimizer1D::~GSLMinimizer1D()
{
   // destructor: clean up minimizer and function pointers

   if (fMinimizer) delete fMinimizer;
   if (fFunction)  delete  fFunction;
}

GSLMinimizer1D::GSLMinimizer1D(const GSLMinimizer1D &): IMinimizer1D()
{
   // dummy copy ctr
}

GSLMinimizer1D & GSLMinimizer1D::operator = (const GSLMinimizer1D &rhs)
{
   // dummy operator =
   if (this == &rhs) return *this;  // time saving self-test
   return *this;
}

void GSLMinimizer1D::SetFunction(  GSLFuncPointer f, void * p, double xmin, double xlow, double xup) {
   // set the function to be minimized
   assert(fFunction);
   assert(fMinimizer);
   fXlow = xlow;
   fXup = xup;
   fXmin = xmin;
   fFunction->SetFuncPointer( f );
   fFunction->SetParams( p );

#ifdef DEBUG
   std::cout << " [ "<< xlow << " , " << xup << " ]" << std::endl;
#endif

   int status = gsl_min_fminimizer_set( fMinimizer->Get(), fFunction->GetFunc(), xmin, xlow, xup);
   if (status != GSL_SUCCESS)
      std::cerr <<"GSLMinimizer1D: Error:  Interval [ "<< xlow << " , " << xup << " ] does not contain a minimum" << std::endl;

   fIsSet = true;
   fStatus = -1;
   return;
}

int GSLMinimizer1D::Iterate() {
   // perform an iteration and update values
   if (!fIsSet) {
      std::cerr << "GSLMinimizer1D- Error: Function has not been set in Minimizer" << std::endl;
      return -1;
   }

   int status =  gsl_min_fminimizer_iterate(fMinimizer->Get());
   // update values
   fXmin = gsl_min_fminimizer_x_minimum(fMinimizer->Get() );
   fMin = gsl_min_fminimizer_f_minimum(fMinimizer->Get() );
   // update interval values
   fXlow =  gsl_min_fminimizer_x_lower(fMinimizer->Get() );
   fXup =  gsl_min_fminimizer_x_upper(fMinimizer->Get() );
   fLow =  gsl_min_fminimizer_f_lower(fMinimizer->Get() );
   fUp =  gsl_min_fminimizer_f_upper(fMinimizer->Get() );
   return status;
}

double GSLMinimizer1D::XMinimum() const {
   // return x value at function minimum
   return fXmin;
}

double GSLMinimizer1D::XLower() const {
   // return lower x value of bracketing interval
   return fXlow;
}

double GSLMinimizer1D::XUpper() const {
   // return upper x value of bracketing interval
   return fXup;
}

double GSLMinimizer1D::FValMinimum() const {
   // return function value at minimum
   return fMin;
}

double GSLMinimizer1D::FValLower() const {
   // return function value at x lower
   return fLow;
}

double GSLMinimizer1D::FValUpper() const {
   // return function value at x upper
   return fUp;
}

const char * GSLMinimizer1D::Name() const {
   // return name of minimization algorithm
   return gsl_min_fminimizer_name(fMinimizer->Get() );
}

bool GSLMinimizer1D::Minimize (int maxIter, double absTol, double relTol)
{
   // find the minimum via multiple iterations
   fStatus = -1;
   int iter = 0;
   int status = 0;
   do {
      iter++;
      status = Iterate();
      if (status != GSL_SUCCESS) {
         MATH_ERROR_MSG("GSLMinimizer1D::Minimize","error returned when performing an iteration");
         fStatus = status;
         return false;
      }

#ifdef DEBUG
      std::cout << "Min1D - iteration " << iter << " interval : [ " << fXlow << "  , " << fXup << " ]  min = " << fXmin
                << " fmin " << fMin << " f(a) " << fLow << " f(b) " << fUp << std::endl;
#endif

      status =  TestInterval(fXlow, fXup, absTol, relTol);
      if (status == GSL_SUCCESS) {
         fIter = iter;
         fStatus = status;
         return true;
      }
   }
   while (status == GSL_CONTINUE && iter < maxIter);
   if (status == GSL_CONTINUE) {
      double tol = std::abs(fXup-fXlow);
      MATH_INFO_MSGVAL("GSLMinimizer1D::Minimize","exceeded max iterations, reached tolerance is not sufficient",tol);
   }
   fStatus = status;
   return false;
}

int GSLMinimizer1D::TestInterval( double xlow, double xup, double epsAbs, double epsRel) {
// static function to test interval
   return gsl_min_test_interval(xlow, xup, epsAbs, epsRel);
}

} // end namespace Math

} // end namespace ROOT

<|endoftext|>


<commit_before>/*
 * gnoproj
 *
 * Copyright (c) 2013-2014 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Stéphane Flotron <s.flotron@foxel.ch>
 *
 * Contributor(s):
 *
 *      Luc Deschenaux <luc.deschenaux@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

#include "gnoproj.hpp"

using namespace std;
using namespace cv;
using namespace elphelphg;

int main(int argc, char** argv) {

    /* Usage branch */
    if ( argc<3 || argc>4 || !strcmp( argv[1], "help" ) || !strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")  ) {
        /* Display help */
        printf( "Usage : %s <imagej_prefs_xml> <input_image> [ <focal> ]\n\n",argv[0]);
        return 1;
    }

    // load inputs
    char *imagej_prefs_xml=argv[1];  //imagej xml configuration file
    char *input_image_filename=argv[2]; // eqr image (input) filename
    std::string output_image_filename; // output image filename

    // check is a focal length is given, and update method if necessary
    int  normalizedFocal(0);  // gnomonic projection method. 0 elphel method (default), 1 with constant focal
    double focal = 0.0;       // focal length (in mm)
    double minFocal = 0.05 ;  // lower bound for focal length
    double maxFocal = 500.0;  // upper bound for focal length
    std::string inputFocal((argc==4)?argv[3]:"");

    // verify if input is present, and if yes, if it is consistant
    if(inputFocal.length())
    {
      focal  = atof(inputFocal.c_str());
      normalizedFocal = 1;

      // check input focal
      if( focal < minFocal || focal > maxFocal)
      {
        std::cerr << "Focal length is less than " << minFocal << " mm or bigger than " << maxFocal << " mm. ";
        std::cerr << "Input focal is " << inputFocal << endl;
        return 0;
      }
    }

    // now load image, and do gnomonic projection
    try {
      CameraArray e4pi(CameraArray::EYESIS4PI_CAMERA,imagej_prefs_xml);

      struct utils::imagefile_info *info=utils::imagefile_parsename(input_image_filename);

      int channel_index=atoi(info->channel);
      Channel *channel=e4pi.channel(channel_index);
      EqrData *eqr=channel->eqr;
      SensorData *sensor=channel->sensor;

      // load image
      IplImage* eqr_img = cvLoadImage(input_image_filename, CV_LOAD_IMAGE_COLOR );

       /* Initialize output image structure */
       IplImage* out_img = cvCreateImage( cvSize( channel->sensor->pixelCorrectionWidth, channel->sensor->pixelCorrectionHeight ), IPL_DEPTH_8U , eqr_img->nChannels );

      if(!normalizedFocal){
          /* Gnomonic projection of the equirectangular tile */
          lg_ttg_uc(
              ( inter_C8_t *) eqr_img->imageData,
              eqr_img->width,
              eqr_img->height,
              eqr_img->nChannels,
              ( inter_C8_t *) out_img->imageData,
              out_img->width,
              out_img->height,
              out_img->nChannels,
              sensor->px0,
              sensor->py0,
              eqr->imageFullWidth,
              eqr->imageFullLength-1, // there's an extra pixel for wrapping
              eqr->xPosition,
              eqr->yPosition,
              rad(sensor->roll),
              rad(sensor->azimuth),
              rad(sensor->elevation),
              rad(sensor->heading),
              0.001*sensor->pixelSize,
              sensor->focalLength,
              li_bilinearf
          );

          // create output image name
          output_image_filename+=std::string(info->dir)+"/"+info->timestamp+"-"+info->channel+"-RECT-SENSOR."+info->extension;
      }
      else
      {
        /* Gnomonic projection of the equirectangular tile */
         lg_ttg_focal(
            ( inter_C8_t *) eqr_img->imageData,
            eqr_img->width,
            eqr_img->height,
            eqr_img->nChannels,
            ( inter_C8_t *) out_img->imageData,
            out_img->width,
            out_img->height,
            out_img->nChannels,
            eqr->imageFullWidth,
            eqr->imageFullLength-1,
            eqr->xPosition,
            eqr->yPosition,
            rad(sensor->azimuth)+rad(sensor->heading)+LG_PI,
            rad(sensor->elevation),
            rad(sensor->roll),
            focal,
            0.001*sensor->pixelSize,
            li_bilinearf
          );

          // create output image name
          output_image_filename+=std::string(info->dir)+"/"+info->timestamp+"-"+info->channel+"-RECT-CONFOC."+info->extension;
      }

      /* Gnomonic image exportation */
      cvSaveImage(output_image_filename.c_str() , out_img, NULL );

    } catch(std::exception &e) {
      std::cerr << e.what() << std::endl;
      return 1;
    } catch(std::string &msg) {
      std::cerr << msg << std::endl;
      return 1;
    } catch(...) {
      std::cerr << "unhandled exception\n";
      return 1;
    }
}
<commit_msg>use bicubic interpolation instead of bilinear<commit_after>/*
 * gnoproj
 *
 * Copyright (c) 2013-2014 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Stéphane Flotron <s.flotron@foxel.ch>
 *
 * Contributor(s):
 *
 *      Luc Deschenaux <luc.deschenaux@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

#include "gnoproj.hpp"

using namespace std;
using namespace cv;
using namespace elphelphg;

int main(int argc, char** argv) {

    /* Usage branch */
    if ( argc<3 || argc>4 || !strcmp( argv[1], "help" ) || !strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")  ) {
        /* Display help */
        printf( "Usage : %s <imagej_prefs_xml> <input_image> [ <focal> ]\n\n",argv[0]);
        return 1;
    }

    // load inputs
    char *imagej_prefs_xml=argv[1];  //imagej xml configuration file
    char *input_image_filename=argv[2]; // eqr image (input) filename
    std::string output_image_filename; // output image filename

    // check is a focal length is given, and update method if necessary
    int  normalizedFocal(0);  // gnomonic projection method. 0 elphel method (default), 1 with constant focal
    double focal = 0.0;       // focal length (in mm)
    double minFocal = 0.05 ;  // lower bound for focal length
    double maxFocal = 500.0;  // upper bound for focal length
    std::string inputFocal((argc==4)?argv[3]:"");

    // verify if input is present, and if yes, if it is consistant
    if(inputFocal.length())
    {
      focal  = atof(inputFocal.c_str());
      normalizedFocal = 1;

      // check input focal
      if( focal < minFocal || focal > maxFocal)
      {
        std::cerr << "Focal length is less than " << minFocal << " mm or bigger than " << maxFocal << " mm. ";
        std::cerr << "Input focal is " << inputFocal << endl;
        return 0;
      }
    }

    // now load image, and do gnomonic projection
    try {
      CameraArray e4pi(CameraArray::EYESIS4PI_CAMERA,imagej_prefs_xml);

      struct utils::imagefile_info *info=utils::imagefile_parsename(input_image_filename);

      int channel_index=atoi(info->channel);
      Channel *channel=e4pi.channel(channel_index);
      EqrData *eqr=channel->eqr;
      SensorData *sensor=channel->sensor;

      // load image
      IplImage* eqr_img = cvLoadImage(input_image_filename, CV_LOAD_IMAGE_COLOR );

       /* Initialize output image structure */
       IplImage* out_img = cvCreateImage( cvSize( channel->sensor->pixelCorrectionWidth, channel->sensor->pixelCorrectionHeight ), IPL_DEPTH_8U , eqr_img->nChannels );

      if(!normalizedFocal){
          /* Gnomonic projection of the equirectangular tile */
          lg_ttg_uc(
              ( inter_C8_t *) eqr_img->imageData,
              eqr_img->width,
              eqr_img->height,
              eqr_img->nChannels,
              ( inter_C8_t *) out_img->imageData,
              out_img->width,
              out_img->height,
              out_img->nChannels,
              sensor->px0,
              sensor->py0,
              eqr->imageFullWidth,
              eqr->imageFullLength-1, // there's an extra pixel for wrapping
              eqr->xPosition,
              eqr->yPosition,
              rad(sensor->roll),
              rad(sensor->azimuth),
              rad(sensor->elevation),
              rad(sensor->heading),
              0.001*sensor->pixelSize,
              sensor->focalLength,
              li_bicubicf
          );

          // create output image name
          output_image_filename+=std::string(info->dir)+"/"+info->timestamp+"-"+info->channel+"-RECT-SENSOR."+info->extension;
      }
      else
      {
        /* Gnomonic projection of the equirectangular tile */
         lg_ttg_focal(
            ( inter_C8_t *) eqr_img->imageData,
            eqr_img->width,
            eqr_img->height,
            eqr_img->nChannels,
            ( inter_C8_t *) out_img->imageData,
            out_img->width,
            out_img->height,
            out_img->nChannels,
            eqr->imageFullWidth,
            eqr->imageFullLength-1,
            eqr->xPosition,
            eqr->yPosition,
            rad(sensor->azimuth)+rad(sensor->heading)+LG_PI,
            rad(sensor->elevation),
            rad(sensor->roll),
            focal,
            0.001*sensor->pixelSize,
            li_bicubicf
          );

          // create output image name
          output_image_filename+=std::string(info->dir)+"/"+info->timestamp+"-"+info->channel+"-RECT-CONFOC."+info->extension;
      }

      /* Gnomonic image exportation */
      cvSaveImage(output_image_filename.c_str() , out_img, NULL );

    } catch(std::exception &e) {
      std::cerr << e.what() << std::endl;
      return 1;
    } catch(std::string &msg) {
      std::cerr << msg << std::endl;
      return 1;
    } catch(...) {
      std::cerr << "unhandled exception\n";
      return 1;
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2013 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "rule.h"

#include <libaddressinput/address_field.h>
#include <libaddressinput/util/scoped_ptr.h>

#include <cassert>
#include <cstddef>
#include <string>
#include <vector>

#include "grit.h"
#include "grit/libaddressinput_strings.h"
#include "region_data_constants.h"
#include "util/json.h"
#include "util/string_split.h"

namespace i18n {
namespace addressinput {

namespace {

bool ParseToken(char c, AddressField* field) {
  assert(field != NULL);
  switch (c) {
    case 'R':
      *field = COUNTRY;
      return true;
    case 'S':
      *field = ADMIN_AREA;
      return true;
    case 'C':
      *field = LOCALITY;
      return true;
    case 'D':
      *field = DEPENDENT_LOCALITY;
      return true;
    case 'X':
      *field = SORTING_CODE;
      return true;
    case 'Z':
      *field = POSTAL_CODE;
      return true;
    case 'A':
      *field = STREET_ADDRESS;
      return true;
    case 'O':
      *field = ORGANIZATION;
      return true;
    case 'N':
      *field = RECIPIENT;
      return true;
    default:
      return false;
  }
}

// Clears |lines|, parses |format|, and adds the address fields and literals to
// |lines|.
//
// For example, the address format in Finland is "%O%n%N%n%A%nAX-%Z %C%nÅLAND".
// It includes the allowed fields prefixed with %, newlines denoted %n, and the
// extra text that should be included on an envelope. It is parsed into:
// {
//     {ORGANIZATION},
//     {RECIPIENT},
//     {STREET_ADDRESS},
//     {"AX-", POSTAL_CODE, " ", LOCALITY},
//     {"ÅLAND"}
// }
void ParseAddressFieldsFormat(const std::string& format,
                              std::vector<std::vector<FormatElement> >* lines) {
  assert(lines != NULL);
  lines->clear();
  lines->resize(1);

  std::vector<std::string> format_parts;
  SplitString(format, '%', &format_parts);

  // If the address format starts with a literal, then it will be in the first
  // element of |format_parts|. This literal does not begin with % and should
  // not be parsed as a token.
  if (!format_parts.empty() && !format_parts[0].empty()) {
    lines->back().push_back(FormatElement(format_parts[0]));
  }

  // The rest of the elements in |format_parts| begin with %.
  for (size_t i = 1; i < format_parts.size(); ++i) {
    if (format_parts[i].empty()) {
      continue;
    }

    // The first character after % denotes a field or a newline token.
    const char control_character = format_parts[i][0];

    // The rest of the string after the token is a literal.
    const std::string literal = format_parts[i].substr(1);

    AddressField field = COUNTRY;
    if (ParseToken(control_character, &field)) {
      lines->back().push_back(FormatElement(field));
    } else if (control_character == 'n') {
      lines->push_back(std::vector<FormatElement>());
    }

    if (!literal.empty()) {
      lines->back().push_back(FormatElement(literal));
    }
  }
}

// Clears |fields|, parses |required|, and adds the required fields to |fields|.
// For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY,
// SORTING_CODE}.
void ParseAddressFieldsRequired(const std::string& required,
                                std::vector<AddressField>* fields) {
  assert(fields != NULL);
  fields->clear();
  for (size_t i = 0; i < required.length(); ++i) {
    AddressField field = COUNTRY;
    if (ParseToken(required[i], &field)) {
      fields->push_back(field);
    }
  }
}

int GetAdminAreaMessageId(const std::string& admin_area_type, bool error) {
  if (admin_area_type == "area") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_AREA
                 : IDS_LIBADDRESSINPUT_I18N_AREA;
  }
  if (admin_area_type == "county") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_COUNTY_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL;
  }
  if (admin_area_type == "department") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPARTMENT
                 : IDS_LIBADDRESSINPUT_I18N_DEPARTMENT;
  }
  if (admin_area_type == "district") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL;
  }
  if (admin_area_type == "do_si") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DO_SI
                 : IDS_LIBADDRESSINPUT_I18N_DO_SI;
  }
  if (admin_area_type == "emirate") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_EMIRATE
                 : IDS_LIBADDRESSINPUT_I18N_EMIRATE;
  }
  if (admin_area_type == "island") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ISLAND
                 : IDS_LIBADDRESSINPUT_I18N_ISLAND;
  }
  if (admin_area_type == "parish") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PARISH
                 : IDS_LIBADDRESSINPUT_I18N_PARISH;
  }
  if (admin_area_type == "prefecture") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PREFECTURE
                 : IDS_LIBADDRESSINPUT_I18N_PREFECTURE;
  }
  if (admin_area_type == "province") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PROVINCE
                 : IDS_LIBADDRESSINPUT_I18N_PROVINCE;
  }
  if (admin_area_type == "state") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_STATE_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_STATE_LABEL;
  }
  return INVALID_MESSAGE_ID;
}

int GetPostalCodeMessageId(const std::string& postal_code_type, bool error) {
  if (postal_code_type == "postal") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_POSTAL_CODE_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL;
  }
  if (postal_code_type == "zip") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ZIP_CODE_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL;
  }
  return INVALID_MESSAGE_ID;
}

}  // namespace

FormatElement::FormatElement(AddressField field)
    : field(field), literal() {}

FormatElement::FormatElement(const std::string& literal)
    : field(COUNTRY), literal(literal) {
  assert(!literal.empty());
}

FormatElement::~FormatElement() {}

bool FormatElement::operator==(const FormatElement& other) const {
  return field == other.field && literal == other.literal;
}

Rule::Rule()
    : format_(),
      required_(),
      sub_keys_(),
      languages_(),
      language_(),
      postal_code_format_(),
      admin_area_name_message_id_(INVALID_MESSAGE_ID),
      postal_code_name_message_id_(INVALID_MESSAGE_ID) {}

Rule::~Rule() {}

// static
const Rule& Rule::GetDefault() {
  // Allocated once and leaked on shutdown.
  static Rule* default_rule = NULL;
  if (default_rule == NULL) {
    default_rule = new Rule;
    default_rule->ParseSerializedRule(
        RegionDataConstants::GetDefaultRegionData());
  }
  return *default_rule;
}

void Rule::CopyFrom(const Rule& rule) {
  format_ = rule.format_;
  required_ = rule.required_;
  sub_keys_ = rule.sub_keys_;
  languages_ = rule.languages_;
  language_ = rule.language_;
  postal_code_format_ = rule.postal_code_format_;
  admin_area_name_message_id_ = rule.admin_area_name_message_id_;
  invalid_admin_area_message_id_ = rule.invalid_admin_area_message_id_;
  postal_code_name_message_id_ = rule.postal_code_name_message_id_;
  invalid_postal_code_message_id_ = rule.invalid_postal_code_message_id_;
}

bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
  scoped_ptr<Json> json(Json::Build());
  if (!json->ParseObject(serialized_rule)) {
    return false;
  }
  ParseJsonRule(*json);
  return true;
}

void Rule::ParseJsonRule(const Json& json_rule) {
  std::string value;
  if (json_rule.GetStringValueForKey("fmt", &value)) {
    ParseAddressFieldsFormat(value, &format_);
  }

  if (json_rule.GetStringValueForKey("require", &value)) {
    ParseAddressFieldsRequired(value, &required_);
  }

  // Used as a separator in a list of items. For example, the list of supported
  // languages can be "de~fr~it".
  static const char kSeparator = '~';
  if (json_rule.GetStringValueForKey("sub_keys", &value)) {
    SplitString(value, kSeparator, &sub_keys_);
  }

  if (json_rule.GetStringValueForKey("languages", &value)) {
    SplitString(value, kSeparator, &languages_);
  }

  if (json_rule.GetStringValueForKey("lang", &value)) {
    language_ = value;
  }

  if (json_rule.GetStringValueForKey("zip", &value)) {
    postal_code_format_ = value;
  }

  if (json_rule.GetStringValueForKey("state_name_type", &value)) {
    admin_area_name_message_id_ = GetAdminAreaMessageId(value, false);
    invalid_admin_area_message_id_ = GetAdminAreaMessageId(value, true);
  }

  if (json_rule.GetStringValueForKey("zip_name_type", &value)) {
    postal_code_name_message_id_ = GetPostalCodeMessageId(value, false);
    invalid_postal_code_message_id_ = GetPostalCodeMessageId(value, true);
  }
}

int Rule::GetInvalidFieldMessageId(AddressField field) const {
  switch (field) {
    case ADMIN_AREA:
      return invalid_admin_area_message_id_;
    case LOCALITY:
      return IDS_LIBADDRESSINPUT_I18N_INVALID_LOCALITY_LABEL;
    case DEPENDENT_LOCALITY:
      return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL;
    case POSTAL_CODE:
      return invalid_postal_code_message_id_;
    default:
      return IDS_LIBADDRESSINPUT_I18N_INVALID_ENTRY;
  }
}

}  // namespace addressinput
}  // namespace i18n
<commit_msg>libaddressinput - minor optimization: don't copy a couple of small strings<commit_after>// Copyright (C) 2013 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "rule.h"

#include <libaddressinput/address_field.h>
#include <libaddressinput/util/scoped_ptr.h>

#include <cassert>
#include <cstddef>
#include <string>
#include <vector>

#include "grit.h"
#include "grit/libaddressinput_strings.h"
#include "region_data_constants.h"
#include "util/json.h"
#include "util/string_split.h"

namespace i18n {
namespace addressinput {

namespace {

bool ParseToken(char c, AddressField* field) {
  assert(field != NULL);
  switch (c) {
    case 'R':
      *field = COUNTRY;
      return true;
    case 'S':
      *field = ADMIN_AREA;
      return true;
    case 'C':
      *field = LOCALITY;
      return true;
    case 'D':
      *field = DEPENDENT_LOCALITY;
      return true;
    case 'X':
      *field = SORTING_CODE;
      return true;
    case 'Z':
      *field = POSTAL_CODE;
      return true;
    case 'A':
      *field = STREET_ADDRESS;
      return true;
    case 'O':
      *field = ORGANIZATION;
      return true;
    case 'N':
      *field = RECIPIENT;
      return true;
    default:
      return false;
  }
}

// Clears |lines|, parses |format|, and adds the address fields and literals to
// |lines|.
//
// For example, the address format in Finland is "%O%n%N%n%A%nAX-%Z %C%nÅLAND".
// It includes the allowed fields prefixed with %, newlines denoted %n, and the
// extra text that should be included on an envelope. It is parsed into:
// {
//     {ORGANIZATION},
//     {RECIPIENT},
//     {STREET_ADDRESS},
//     {"AX-", POSTAL_CODE, " ", LOCALITY},
//     {"ÅLAND"}
// }
void ParseAddressFieldsFormat(const std::string& format,
                              std::vector<std::vector<FormatElement> >* lines) {
  assert(lines != NULL);
  lines->clear();
  lines->resize(1);

  std::vector<std::string> format_parts;
  SplitString(format, '%', &format_parts);

  // If the address format starts with a literal, then it will be in the first
  // element of |format_parts|. This literal does not begin with % and should
  // not be parsed as a token.
  if (!format_parts.empty() && !format_parts[0].empty()) {
    lines->back().push_back(FormatElement(format_parts[0]));
  }

  // The rest of the elements in |format_parts| begin with %.
  for (size_t i = 1; i < format_parts.size(); ++i) {
    if (format_parts[i].empty()) {
      continue;
    }

    // The first character after % denotes a field or a newline token.
    const char control_character = format_parts[i][0];

    // The rest of the string after the token is a literal.
    const std::string literal = format_parts[i].substr(1);

    AddressField field = COUNTRY;
    if (ParseToken(control_character, &field)) {
      lines->back().push_back(FormatElement(field));
    } else if (control_character == 'n') {
      lines->push_back(std::vector<FormatElement>());
    }

    if (!literal.empty()) {
      lines->back().push_back(FormatElement(literal));
    }
  }
}

// Clears |fields|, parses |required|, and adds the required fields to |fields|.
// For example, parses "SCDX" into {ADMIN_AREA, LOCALITY, DEPENDENT_LOCALITY,
// SORTING_CODE}.
void ParseAddressFieldsRequired(const std::string& required,
                                std::vector<AddressField>* fields) {
  assert(fields != NULL);
  fields->clear();
  for (size_t i = 0; i < required.length(); ++i) {
    AddressField field = COUNTRY;
    if (ParseToken(required[i], &field)) {
      fields->push_back(field);
    }
  }
}

int GetAdminAreaMessageId(const std::string& admin_area_type, bool error) {
  if (admin_area_type == "area") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_AREA
                 : IDS_LIBADDRESSINPUT_I18N_AREA;
  }
  if (admin_area_type == "county") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_COUNTY_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_COUNTY_LABEL;
  }
  if (admin_area_type == "department") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPARTMENT
                 : IDS_LIBADDRESSINPUT_I18N_DEPARTMENT;
  }
  if (admin_area_type == "district") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_DEPENDENT_LOCALITY_LABEL;
  }
  if (admin_area_type == "do_si") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_DO_SI
                 : IDS_LIBADDRESSINPUT_I18N_DO_SI;
  }
  if (admin_area_type == "emirate") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_EMIRATE
                 : IDS_LIBADDRESSINPUT_I18N_EMIRATE;
  }
  if (admin_area_type == "island") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ISLAND
                 : IDS_LIBADDRESSINPUT_I18N_ISLAND;
  }
  if (admin_area_type == "parish") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PARISH
                 : IDS_LIBADDRESSINPUT_I18N_PARISH;
  }
  if (admin_area_type == "prefecture") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PREFECTURE
                 : IDS_LIBADDRESSINPUT_I18N_PREFECTURE;
  }
  if (admin_area_type == "province") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_PROVINCE
                 : IDS_LIBADDRESSINPUT_I18N_PROVINCE;
  }
  if (admin_area_type == "state") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_STATE_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_STATE_LABEL;
  }
  return INVALID_MESSAGE_ID;
}

int GetPostalCodeMessageId(const std::string& postal_code_type, bool error) {
  if (postal_code_type == "postal") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_POSTAL_CODE_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_POSTAL_CODE_LABEL;
  }
  if (postal_code_type == "zip") {
    return error ? IDS_LIBADDRESSINPUT_I18N_INVALID_ZIP_CODE_LABEL
                 : IDS_LIBADDRESSINPUT_I18N_ZIP_CODE_LABEL;
  }
  return INVALID_MESSAGE_ID;
}

}  // namespace

FormatElement::FormatElement(AddressField field)
    : field(field), literal() {}

FormatElement::FormatElement(const std::string& literal)
    : field(COUNTRY), literal(literal) {
  assert(!literal.empty());
}

FormatElement::~FormatElement() {}

bool FormatElement::operator==(const FormatElement& other) const {
  return field == other.field && literal == other.literal;
}

Rule::Rule()
    : format_(),
      required_(),
      sub_keys_(),
      languages_(),
      language_(),
      postal_code_format_(),
      admin_area_name_message_id_(INVALID_MESSAGE_ID),
      postal_code_name_message_id_(INVALID_MESSAGE_ID) {}

Rule::~Rule() {}

// static
const Rule& Rule::GetDefault() {
  // Allocated once and leaked on shutdown.
  static Rule* default_rule = NULL;
  if (default_rule == NULL) {
    default_rule = new Rule;
    default_rule->ParseSerializedRule(
        RegionDataConstants::GetDefaultRegionData());
  }
  return *default_rule;
}

void Rule::CopyFrom(const Rule& rule) {
  format_ = rule.format_;
  required_ = rule.required_;
  sub_keys_ = rule.sub_keys_;
  languages_ = rule.languages_;
  language_ = rule.language_;
  postal_code_format_ = rule.postal_code_format_;
  admin_area_name_message_id_ = rule.admin_area_name_message_id_;
  invalid_admin_area_message_id_ = rule.invalid_admin_area_message_id_;
  postal_code_name_message_id_ = rule.postal_code_name_message_id_;
  invalid_postal_code_message_id_ = rule.invalid_postal_code_message_id_;
}

bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
  scoped_ptr<Json> json(Json::Build());
  if (!json->ParseObject(serialized_rule)) {
    return false;
  }
  ParseJsonRule(*json);
  return true;
}

void Rule::ParseJsonRule(const Json& json_rule) {
  std::string value;
  if (json_rule.GetStringValueForKey("fmt", &value)) {
    ParseAddressFieldsFormat(value, &format_);
  }

  if (json_rule.GetStringValueForKey("require", &value)) {
    ParseAddressFieldsRequired(value, &required_);
  }

  // Used as a separator in a list of items. For example, the list of supported
  // languages can be "de~fr~it".
  static const char kSeparator = '~';
  if (json_rule.GetStringValueForKey("sub_keys", &value)) {
    SplitString(value, kSeparator, &sub_keys_);
  }

  if (json_rule.GetStringValueForKey("languages", &value)) {
    SplitString(value, kSeparator, &languages_);
  }

  if (json_rule.GetStringValueForKey("lang", &value)) {
    language_.swap(value);
  }

  if (json_rule.GetStringValueForKey("zip", &value)) {
    postal_code_format_.swap(value);
  }

  if (json_rule.GetStringValueForKey("state_name_type", &value)) {
    admin_area_name_message_id_ = GetAdminAreaMessageId(value, false);
    invalid_admin_area_message_id_ = GetAdminAreaMessageId(value, true);
  }

  if (json_rule.GetStringValueForKey("zip_name_type", &value)) {
    postal_code_name_message_id_ = GetPostalCodeMessageId(value, false);
    invalid_postal_code_message_id_ = GetPostalCodeMessageId(value, true);
  }
}

int Rule::GetInvalidFieldMessageId(AddressField field) const {
  switch (field) {
    case ADMIN_AREA:
      return invalid_admin_area_message_id_;
    case LOCALITY:
      return IDS_LIBADDRESSINPUT_I18N_INVALID_LOCALITY_LABEL;
    case DEPENDENT_LOCALITY:
      return IDS_LIBADDRESSINPUT_I18N_INVALID_DEPENDENT_LOCALITY_LABEL;
    case POSTAL_CODE:
      return invalid_postal_code_message_id_;
    default:
      return IDS_LIBADDRESSINPUT_I18N_INVALID_ENTRY;
  }
}

}  // namespace addressinput
}  // namespace i18n
<|endoftext|>


<commit_before>#include <arduino.h>
#include "pulsemover.h"

int DURATION = 1000;  // Pulse should be given for one second.
/* int BASE = 1; */
/* int ACTUATED = 2; */

PulseMover::PulseMover(int pin_base,
                       int pin_actuated){
  PulseMover::pin_base = pin_base;
  PulseMover::pin_actuated = pin_actuated;

  stop_pulse_again = millis();
  done = true;
}

void PulseMover::init(){
  pinMode(pin_base, OUTPUT);
  digitalWrite(pin_base, LOW);
  pinMode(pin_actuated, OUTPUT);
  digitalWrite(pin_actuated, LOW);
  move_to_base();
  /* digitalWrite(pin_base, HIGH); */
  /* stop_pulse_again = millis() + PERIOD; */
}

void PulseMover::move_to_base(){
  done = false;
  digitalWrite(pin_actuated, LOW);
  digitalWrite(pin_base, HIGH);
  stop_pulse_again = millis() + DURATION;
}

void PulseMover::move_to_actuated(){
  done = false;
  digitalWrite(pin_base, LOW);
  digitalWrite(pin_actuated, HIGH);
  stop_pulse_again = millis() + DURATION;
}

void PulseMover::perhaps_update(){
  if (!done && stop_pulse_again < millis()) {
    digitalWrite(pin_base, LOW);
    digitalWrite(pin_actuated, LOW);
    done = true;
  }
}
<commit_msg>cleanup<commit_after>#include <arduino.h>
#include "pulsemover.h"

int DURATION = 1000;  // Pulse should be given for one second.

PulseMover::PulseMover(int pin_base,
                       int pin_actuated){
  PulseMover::pin_base = pin_base;
  PulseMover::pin_actuated = pin_actuated;

  stop_pulse_again = millis();
  done = true;
}

void PulseMover::init(){
  pinMode(pin_base, OUTPUT);
  digitalWrite(pin_base, LOW);
  pinMode(pin_actuated, OUTPUT);
  digitalWrite(pin_actuated, LOW);
  move_to_base();
  /* digitalWrite(pin_base, HIGH); */
  /* stop_pulse_again = millis() + PERIOD; */
}

void PulseMover::move_to_base(){
  done = false;
  digitalWrite(pin_actuated, LOW);
  digitalWrite(pin_base, HIGH);
  stop_pulse_again = millis() + DURATION;
}

void PulseMover::move_to_actuated(){
  done = false;
  digitalWrite(pin_base, LOW);
  digitalWrite(pin_actuated, HIGH);
  stop_pulse_again = millis() + DURATION;
}

void PulseMover::perhaps_update(){
  if (!done && stop_pulse_again < millis()) {
    digitalWrite(pin_base, LOW);
    digitalWrite(pin_actuated, LOW);
    done = true;
  }
}
<|endoftext|>


<commit_before>// MS WARNINGS MACRO
#define _SCL_SECURE_NO_WARNINGS

// Macro: Program Settings
#define ENABLE_NETWORK_IO 1

#include <iostream>
#include <deque>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/program_options.hpp>
#include "data_type.hpp"
#include "pixel_sorter.hpp"
#include "ppm_reader.hpp"
#include "splitter.hpp"
#include "algorithm.hpp"
#include "algorithm_2.hpp"
#include "gui.hpp"
#include "network.hpp"
#include "test_tool.hpp"

#include <sort_algorithm/yrange2.hpp>
#include <sort_algorithm/yrange5.hpp>
#include <sort_algorithm/genetic.hpp>
#include <sort_algorithm/Murakami.hpp>

class position_manager : boost::noncopyable
{
public:
    typedef question_data position_type;

    position_manager() = default;
    virtual ~position_manager() = default;

    template<class T>
    void add(T && pos)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        items_.push_back(std::forward<T>(pos));
    }

    position_type get()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        auto res = items_.front();
        items_.pop_front();
        return res;
    }

    bool empty()
    {
        return items_.empty();
    }

private:
    std::mutex mutex_;
    std::deque<position_type> items_;
};

class analyzer : boost::noncopyable
{
public:
    explicit analyzer(
        std::string const& server_addr,
        int const problem_id, std::string const& player_id,
        bool const is_auto, bool const is_blur
        )
        : client_(server_addr), problem_id_(problem_id), player_id_(player_id),
          is_auto_(is_auto), is_blur_(is_blur)
    {
    }
    virtual ~analyzer() = default;

    void operator() (position_manager& manager)
    {
        splitter sp;

        // 問題文の入手
        raw_data_ = get_raw_question();
        data_     = get_skelton_question(raw_data_);

        // 2次元画像に分割
        split_image_ = sp.split_image(raw_data_);
        if(is_blur_) split_image_ = sp.split_image_gaussianblur(split_image_);
        auto const image_comp = sorter_.image_comp(raw_data_, split_image_);
		auto const image_comp_dx = sorter_dx.image_comp(raw_data_, split_image_);
        // 原画像推測部
        yrange2 yrange2_(raw_data_, image_comp);
        Murakami murakami_(raw_data_, image_comp,true);
        // GUI Threadの起動
        gui::manager gui_thread(
            [this, &manager](std::vector<std::vector<point_type>> const& data)
            {
                // 回答としてマーク -> 回答ジョブに追加
                auto clone = data_.clone();
                clone.block = data;
                manager.add(convert_block(clone));
            });

        // YRange2 -> YRange5 Thread
        boost::thread y_thread(
            [&, this]()
            {
                // YRange2
                auto yrange2_resolve = yrange2_();
                if (!yrange2_resolve.empty())
		        {
                    // Shoot
                    if(is_auto_)
                    {
                        auto clone = data_.clone();
                        clone.block = yrange2_resolve[0].points;
                        manager.add(convert_block(clone));
                    }

                    // GUI
			        for (int y2 = yrange2_resolve.size() - 1; y2 >= 0; --y2)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange2_resolve.at(y2).points, "yrange2")
                            );
			        }
		        }

                // YRange5
                auto yrange5_resolve = yrange5(raw_data_, image_comp)(yrange2_.sorted_matrix());
                if (!yrange5_resolve.empty())
		        {
                    // GUI
			        for (int y5 = yrange5_resolve.size() - 1; y5 >= 0; --y5)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange5_resolve.at(y5).points, "yrange5")
                            );
			        }
                }
            });

        // Murakami Thread
        boost::thread m_thread(
            [&]()
            {
                // Murakami
			std::cout << "村上モード" << std::endl;
                auto murakami_resolve = murakami_()[0].points;
				std::vector<std::vector<point_type>> murakami_dx_resolve, murakami_w_resolve, murakami_dx_w_resolve;
				if (!murakami_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_resolve, "Murakami"));
				if (murakami_resolve.empty()){
					std::cout << "デラックス村上モード" << std::endl;
					Murakami murakami_dx(raw_data_, image_comp_dx, true);
					murakami_dx_resolve = murakami_dx()[0].points;
					if (!murakami_dx_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_resolve, "Murakami_dx"));
					if (murakami_dx_resolve.empty()){
						std::cout << "W村上モード" << std::endl;
						Murakami murakami_w(raw_data_, image_comp, false);
						murakami_w_resolve = murakami_w()[0].points;
						if (!murakami_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_w_resolve, "Murakami_w"));
						if (murakami_w_resolve.empty()){
							std::cout << "デラックスW村上モード" << std::endl;
							Murakami murakami_dx_w(raw_data_, image_comp_dx, false);
							murakami_dx_w_resolve = murakami_w()[0].points;
							if (!murakami_dx_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_w_resolve, "Murakami_dx_w"));
						}
					}
				}
            });

        gui_thread.push_back(
            boost::bind(gui::make_mansort_window, split_image_, "Yor are the sorter!!! Sort this!")
            );

        // 各Threadの待機
        y_thread.join();
        m_thread.join();
        gui_thread.wait_all_window();
    }

    std::string submit(answer_type const& ans) const
    {
        auto submit_result = client_.submit(problem_id_, player_id_, ans);
        return submit_result.get();
    }

private:
    question_raw_data get_raw_question() const
    {
#if ENABLE_NETWORK_IO
        // ネットワーク通信から
        std::string const data = client_.get_problem(problem_id_).get();
        return ppm_reader().from_data(data);
#else
        // ファイルから
        std::string const path("prob01.ppm");
        return ppm_reader().from_file(path);
#endif
    }

    question_data get_skelton_question(question_raw_data const& raw) const
    {
        question_data formed = {
            problem_id_,
            player_id_,
            raw.split_num,
            raw.selectable_num,
            raw.cost.first,
            raw.cost.second,
            std::vector<std::vector<point_type>>()
        };

        return formed;
    }

    question_data convert_block(question_data const& data) const
    {
        auto res = data.clone();

        for(int i = 0; i < data.size.second; ++i)
        {
            for(int j = 0; j < data.size.first; ++j)
            {
                auto const& target = data.block[i][j];
                res.block[target.y][target.x] = point_type{j, i};
		}
        }

        return res;
    }

    int const problem_id_;
    std::string const player_id_;
    bool const is_auto_;
    bool const is_blur_;

    question_raw_data raw_data_;
    question_data         data_;
    split_image_type  split_image_;
	split_image_type  split_image_gaussianblur;

    mutable network::client client_;
    pixel_sorter<yrange5> sorter_;
	pixel_sorter<yrange2> sorter_dx;
};

void submit_func(question_data question, analyzer const& analyze)
{
    algorithm algo;
    algorithm_2 algo2;
    algo.reset(question);

    auto const answer = algo.get();
    if(answer) // 解が見つかった
    {
#if ENABLE_NETWORK_IO
        // TODO: 前より良くなったら提出など(普通にいらないかも．提出前に目grepしてるわけだし)
        auto result = analyze.submit(answer.get());
        std::cout << "Submit Result: " << result << std::endl;

	// FIXME: 汚いしセグフォする
	int wrong_number = std::stoi(result.substr(result.find(" ")));
	if(wrong_number == 0)
	{
        algo2.reset(question);
		auto const answer = algo2.get();
		if (answer)
		{
			auto result = analyze.submit(answer.get());
			std::cout << "Submit Result: " << result << std::endl;
			std::cout << "勝った！" << std::endl;
		}
	}
#else
        test_tool::emulator emu(question);
        auto result = emu.start(answer.get());
        std::cout << "Wrong: " << result.wrong << std::endl;
        std::cout << "Cost : " << result.cost  << std::endl;
        std::cout << "---" << std::endl;
#endif
    }
}

int main(int const argc, char const* argv[])
{
    std::string server_addr;
	int         problemid = 0;
    auto const  token = "3935105806";
    bool        is_auto;
    bool        is_blur;

    try
    {
        namespace po = boost::program_options;
        po::options_description opt("option");
        opt.add_options()
            ("help,h"    , "produce help message")
            ("auto,a"    , "auto submit flag")
            ("blur,b"    , "gaussian blur to image")
#if ENABLE_NETWORK_IO
            ("server,s"  , po::value<std::string>(&server_addr), "(require)set server ip address")
            ("problem,p" , po::value<int>(&problemid)          , "(require)set problem_id")
#endif
            ;

        po::variables_map argmap;
        po::store(po::parse_command_line(argc, argv, opt), argmap);
        po::notify(argmap);

#if ENABLE_NETWORK_IO
        if(argmap.count("help") || !argmap.count("server") || !argmap.count("problem"))
#else
        if(argmap.count("help"))
#endif
        {
            std::cout << opt << std::endl;
            return 0;
        }

        is_auto = argmap.count("auto");
        is_blur = argmap.count("blur");
    }
    catch(boost::program_options::error_with_option_name const& e)
    {
        std::cout << e.what() << std::endl;
        std::exit(-1);
    }

    analyzer         analyze(server_addr, problemid, token, is_auto, is_blur);
    position_manager manager;

    boost::thread thread(boost::bind(&analyzer::operator(), &analyze, std::ref(manager)));
    boost::thread_group submit_threads;

    while(thread.joinable())
    {
        if(!manager.empty())
        {
            auto question = manager.get();

            // 手順探索部
            submit_threads.create_thread(
                boost::bind(submit_func, question, boost::ref(analyze))
                );
        }
    }

    thread.join();
    submit_threads.join_all();

    return 0;
}

<commit_msg>手動並び替えの場合にも，ぼかしが入らないように．<commit_after>// MS WARNINGS MACRO
#define _SCL_SECURE_NO_WARNINGS

// Macro: Program Settings
#define ENABLE_NETWORK_IO 1

#include <iostream>
#include <deque>
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/program_options.hpp>
#include "data_type.hpp"
#include "pixel_sorter.hpp"
#include "ppm_reader.hpp"
#include "splitter.hpp"
#include "algorithm.hpp"
#include "algorithm_2.hpp"
#include "gui.hpp"
#include "network.hpp"
#include "test_tool.hpp"

#include <sort_algorithm/yrange2.hpp>
#include <sort_algorithm/yrange5.hpp>
#include <sort_algorithm/genetic.hpp>
#include <sort_algorithm/Murakami.hpp>

class position_manager : boost::noncopyable
{
public:
    typedef question_data position_type;

    position_manager() = default;
    virtual ~position_manager() = default;

    template<class T>
    void add(T && pos)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        items_.push_back(std::forward<T>(pos));
    }

    position_type get()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        auto res = items_.front();
        items_.pop_front();
        return res;
    }

    bool empty()
    {
        return items_.empty();
    }

private:
    std::mutex mutex_;
    std::deque<position_type> items_;
};

class analyzer : boost::noncopyable
{
public:
    explicit analyzer(
        std::string const& server_addr,
        int const problem_id, std::string const& player_id,
        bool const is_auto, bool const is_blur
        )
        : client_(server_addr), problem_id_(problem_id), player_id_(player_id),
          is_auto_(is_auto), is_blur_(is_blur)
    {
    }
    virtual ~analyzer() = default;

    void operator() (position_manager& manager)
    {
        splitter sp;

        // 問題文の入手
        raw_data_ = get_raw_question();
        data_     = get_skelton_question(raw_data_);

        // 2次元画像に分割
        split_image_ = sp.split_image(raw_data_);

        // compare用の画像を作成
        auto const arranged_split = is_blur_ ? sp.split_image_gaussianblur(split_image_) : split_image_;
        auto const image_comp = sorter_.image_comp(raw_data_, arranged_split);
		auto const image_comp_dx = sorter_dx.image_comp(raw_data_, arranged_split);

        // 原画像推測部
        yrange2 yrange2_(raw_data_, image_comp);
        Murakami murakami_(raw_data_, image_comp,true);

        // GUI Threadの起動
        gui::manager gui_thread(
            [this, &manager](std::vector<std::vector<point_type>> const& data)
            {
                // 回答としてマーク -> 回答ジョブに追加
                auto clone = data_.clone();
                clone.block = data;
                manager.add(convert_block(clone));
            });

        // YRange2 -> YRange5 Thread
        boost::thread y_thread(
            [&, this]()
            {
                // YRange2
                auto yrange2_resolve = yrange2_();
                if (!yrange2_resolve.empty())
		        {
                    // Shoot
                    if(is_auto_)
                    {
                        auto clone = data_.clone();
                        clone.block = yrange2_resolve[0].points;
                        manager.add(convert_block(clone));
                    }

                    // GUI
			        for (int y2 = yrange2_resolve.size() - 1; y2 >= 0; --y2)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange2_resolve.at(y2).points, "yrange2")
                            );
			        }
		        }

                // YRange5
                auto yrange5_resolve = yrange5(raw_data_, image_comp)(yrange2_.sorted_matrix());
                if (!yrange5_resolve.empty())
		        {
                    // GUI
			        for (int y5 = yrange5_resolve.size() - 1; y5 >= 0; --y5)
			        {
                        gui_thread.push_back(
                            boost::bind(gui::make_mansort_window, split_image_, yrange5_resolve.at(y5).points, "yrange5")
                            );
			        }
                }
            });

        // Murakami Thread
        boost::thread m_thread(
            [&]()
            {
                // Murakami
			std::cout << "村上モード" << std::endl;
                auto murakami_resolve = murakami_()[0].points;
				std::vector<std::vector<point_type>> murakami_dx_resolve, murakami_w_resolve, murakami_dx_w_resolve;
				if (!murakami_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_resolve, "Murakami"));
				if (murakami_resolve.empty()){
					std::cout << "デラックス村上モード" << std::endl;
					Murakami murakami_dx(raw_data_, image_comp_dx, true);
					murakami_dx_resolve = murakami_dx()[0].points;
					if (!murakami_dx_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_resolve, "Murakami_dx"));
					if (murakami_dx_resolve.empty()){
						std::cout << "W村上モード" << std::endl;
						Murakami murakami_w(raw_data_, image_comp, false);
						murakami_w_resolve = murakami_w()[0].points;
						if (!murakami_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_w_resolve, "Murakami_w"));
						if (murakami_w_resolve.empty()){
							std::cout << "デラックスW村上モード" << std::endl;
							Murakami murakami_dx_w(raw_data_, image_comp_dx, false);
							murakami_dx_w_resolve = murakami_w()[0].points;
							if (!murakami_dx_w_resolve.empty())gui_thread.push_back(boost::bind(gui::make_mansort_window, split_image_, murakami_dx_w_resolve, "Murakami_dx_w"));
						}
					}
				}
            });

        gui_thread.push_back(
            boost::bind(gui::make_mansort_window, split_image_, "Yor are the sorter!!! Sort this!")
            );

        // 各Threadの待機
        y_thread.join();
        m_thread.join();
        gui_thread.wait_all_window();
    }

    std::string submit(answer_type const& ans) const
    {
        auto submit_result = client_.submit(problem_id_, player_id_, ans);
        return submit_result.get();
    }

private:
    question_raw_data get_raw_question() const
    {
#if ENABLE_NETWORK_IO
        // ネットワーク通信から
        std::string const data = client_.get_problem(problem_id_).get();
        return ppm_reader().from_data(data);
#else
        // ファイルから
        std::string const path("prob01.ppm");
        return ppm_reader().from_file(path);
#endif
    }

    question_data get_skelton_question(question_raw_data const& raw) const
    {
        question_data formed = {
            problem_id_,
            player_id_,
            raw.split_num,
            raw.selectable_num,
            raw.cost.first,
            raw.cost.second,
            std::vector<std::vector<point_type>>()
        };

        return formed;
    }

    question_data convert_block(question_data const& data) const
    {
        auto res = data.clone();

        for(int i = 0; i < data.size.second; ++i)
        {
            for(int j = 0; j < data.size.first; ++j)
            {
                auto const& target = data.block[i][j];
                res.block[target.y][target.x] = point_type{j, i};
		}
        }

        return res;
    }

    int const problem_id_;
    std::string const player_id_;
    bool const is_auto_;
    bool const is_blur_;

    question_raw_data raw_data_;
    question_data         data_;
    split_image_type  split_image_;
	split_image_type  split_image_gaussianblur;

    mutable network::client client_;
    pixel_sorter<yrange5> sorter_;
	pixel_sorter<yrange2> sorter_dx;
};

void submit_func(question_data question, analyzer const& analyze)
{
    algorithm algo;
    algorithm_2 algo2;
    algo.reset(question);

    auto const answer = algo.get();
    if(answer) // 解が見つかった
    {
#if ENABLE_NETWORK_IO
        // TODO: 前より良くなったら提出など(普通にいらないかも．提出前に目grepしてるわけだし)
        auto result = analyze.submit(answer.get());
        std::cout << "Submit Result: " << result << std::endl;

	// FIXME: 汚いしセグフォする
	int wrong_number = std::stoi(result.substr(result.find(" ")));
	if(wrong_number == 0)
	{
        algo2.reset(question);
		auto const answer = algo2.get();
		if (answer)
		{
			auto result = analyze.submit(answer.get());
			std::cout << "Submit Result: " << result << std::endl;
			std::cout << "勝った！" << std::endl;
		}
	}
#else
        test_tool::emulator emu(question);
        auto result = emu.start(answer.get());
        std::cout << "Wrong: " << result.wrong << std::endl;
        std::cout << "Cost : " << result.cost  << std::endl;
        std::cout << "---" << std::endl;
#endif
    }
}

int main(int const argc, char const* argv[])
{
    std::string server_addr;
	int         problemid = 0;
    auto const  token = "3935105806";
    bool        is_auto;
    bool        is_blur;

    try
    {
        namespace po = boost::program_options;
        po::options_description opt("option");
        opt.add_options()
            ("help,h"    , "produce help message")
            ("auto,a"    , "auto submit flag")
            ("blur,b"    , "gaussian blur to image")
#if ENABLE_NETWORK_IO
            ("server,s"  , po::value<std::string>(&server_addr), "(require)set server ip address")
            ("problem,p" , po::value<int>(&problemid)          , "(require)set problem_id")
#endif
            ;

        po::variables_map argmap;
        po::store(po::parse_command_line(argc, argv, opt), argmap);
        po::notify(argmap);

#if ENABLE_NETWORK_IO
        if(argmap.count("help") || !argmap.count("server") || !argmap.count("problem"))
#else
        if(argmap.count("help"))
#endif
        {
            std::cout << opt << std::endl;
            return 0;
        }

        is_auto = argmap.count("auto");
        is_blur = argmap.count("blur");
    }
    catch(boost::program_options::error_with_option_name const& e)
    {
        std::cout << e.what() << std::endl;
        std::exit(-1);
    }

    analyzer         analyze(server_addr, problemid, token, is_auto, is_blur);
    position_manager manager;

    boost::thread thread(boost::bind(&analyzer::operator(), &analyze, std::ref(manager)));
    boost::thread_group submit_threads;

    while(thread.joinable())
    {
        if(!manager.empty())
        {
            auto question = manager.get();

            // 手順探索部
            submit_threads.create_thread(
                boost::bind(submit_func, question, boost::ref(analyze))
                );
        }
    }

    thread.join();
    submit_threads.join_all();

    return 0;
}

<|endoftext|>