<commit_before>#include <fc/string.hpp>
#include <fc/utility.hpp>
#include <fc/fwd_impl.hpp>
#include <fc/exception/exception.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

#include <string>
#include <sstream>
#include <iomanip>
#include <locale>
#include <limits>

/**
 *  Implemented with std::string for now.
 */

namespace fc  {
   class comma_numpunct : public std::numpunct<char>
   {
      protected:
         virtual char do_thousands_sep() const { return ','; }
         virtual std::string do_grouping() const { return "\03"; }
   };

  std::string to_pretty_string( int64_t value )
  {
     std::stringstream ss;
     ss.imbue( {std::locale(), new comma_numpunct} );
     ss << std::fixed << value;
     return ss.str();
  }

#ifdef USE_FC_STRING
  string::string(const char* s, int l) :my(s,l){ }
  string::string(){}
  string::string( const fc::string& c ):my(*c.my) { }
  string::string( string&& m ):my(fc::move(*m.my)) {}
  string::string( const char* c ):my(c){}
  string::string( const_iterator b, const_iterator e ):my(b,e){}
  string::string( const std::string& s ):my(s) {}
  string::string( std::string&& s ):my(fc::move(s)) {}
  string::~string() { }
  string::operator std::string&() { return *my; }
  string::operator const std::string&()const { return *my; }
  char* string::data() { return &my->front(); }

  string::iterator string::begin()            { return &(*this)[0]; }
  string::iterator string::end()              { return &(*this)[size()]; }
  string::const_iterator string::begin()const { return my->c_str(); }
  string::const_iterator string::end()const   { return my->c_str() + my->size(); }

  char&       string::operator[](size_t idx)      { return (*my)[idx]; }
  const char& string::operator[](size_t idx)const { return (*my)[idx]; }

  void       string::reserve(size_t r)           { my->reserve(r); }
  size_t   string::size()const                   { return my->size(); }
  size_t   string::find(char c, size_t p)const { return my->find(c,p); }
  size_t   string::find(const fc::string& str, size_t pos /* = 0 */) const { return my->find(str, pos); }
  size_t   string::find(const char* s, size_t pos /* = 0 */) const { return my->find(s,pos); }
  size_t   string::rfind(char c, size_t p)const { return my->rfind(c,p); }
  size_t   string::rfind(const char* c, size_t p)const { return my->rfind(c,p); }
  size_t   string::rfind(const fc::string& c, size_t p)const { return my->rfind(c,p); }
  size_t   string::find_first_of(const fc::string& str, size_t pos /* = 0 */) const { return my->find_first_of(str, pos); }
  size_t   string::find_first_of(const char* s, size_t pos /* = 0 */) const { return my->find_first_of(s, pos); }

  fc::string& string::replace(size_t pos,  size_t len,  const string& str) { my->replace(pos, len, str); return *this; }
  fc::string& string::replace(size_t pos,  size_t len,  const char* s) { my->replace(pos, len, s); return *this; }

  void       string::clear()                       { my->clear(); }
  void       string::resize( size_t s )          { my->resize(s); }

  fc::string string::substr( size_t start, size_t len )const { return my->substr(start,len); }
  const char* string::c_str()const                        { return my->c_str(); }

  bool    string::operator == ( const char* s )const   { return *my == s; }
  bool    string::operator == ( const string& s )const { return *my == *s.my; }
  bool    string::operator != ( const string& s )const { return *my != *s.my; }

  string& string::operator =( const string& c )          { *my = *c.my; return *this; }
  string& string::operator =( string&& c )               { *my = fc::move( *c.my ); return *this; }

  string& string::operator+=( const string& s )          { *my += *s.my; return *this; }
  string& string::operator+=( char c )                   { *my += c; return *this; }

  bool operator < ( const string& a, const string& b )   { return *a.my < *b.my; }
  string operator + ( const string& s, const string& c ) { return string(s) += c; }
  string operator + ( const string& s, char c ) 	 { return string(s) += c; }
#endif // USE_FC_STRING

  int64_t    to_int64( const fc::string& i )
  {
    try
    {
      return boost::lexical_cast<int64_t>(i.c_str());
    }
    catch( const boost::bad_lexical_cast& e )
    {
      FC_THROW_EXCEPTION( parse_error_exception, "Couldn't parse int64_t" );
    }
    FC_RETHROW_EXCEPTIONS( warn, "${i} => int64_t", ("i",i) )
  }

  uint64_t   to_uint64( const fc::string& i )
  { try {
    try
    {
      return boost::lexical_cast<uint64_t>(i.c_str());
    }
    catch( const boost::bad_lexical_cast& e )
    {
      FC_THROW_EXCEPTION( parse_error_exception, "Couldn't parse uint64_t" );
    }
    FC_RETHROW_EXCEPTIONS( warn, "${i} => uint64_t", ("i",i) )
  } FC_CAPTURE_AND_RETHROW( (i) ) }

  double     to_double( const fc::string& i)
  {
    try
    {
      return boost::lexical_cast<double>(i.c_str());
    }
    catch( const boost::bad_lexical_cast& e )
    {
      FC_THROW_EXCEPTION( parse_error_exception, "Couldn't parse double" );
    }
    FC_RETHROW_EXCEPTIONS( warn, "${i} => double", ("i",i) )
  }

  fc::string to_string(double d)
  {
    // +2 is required to ensure that the double is rounded correctly when read back in.  http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
    std::stringstream ss;
    ss << std::setprecision(std::numeric_limits<double>::digits10 + 2) << std::fixed << d;
    return ss.str();
  }

  fc::string to_string( uint64_t d)
  {
    return boost::lexical_cast<std::string>(d);
  }

  fc::string to_string( int64_t d)
  {
    return boost::lexical_cast<std::string>(d);
  }
  fc::string to_string( uint16_t d)
  {
    return boost::lexical_cast<std::string>(d);
  }
  std::string trim( const std::string& s )
  {
      return boost::algorithm::trim_copy(s);
      /*
      std::string cpy(s);
      boost::algorithm::trim(cpy);
      return cpy;
      */
  }
  std::string to_lower( const std::string& s )
  {
     auto tmp = s;
     boost::algorithm::to_lower(tmp);
     return tmp;
  }
  string trim_and_normalize_spaces( const string& s )
  {
     string result = boost::algorithm::trim_copy( s );
     while( result.find( "  " ) != result.npos )
       boost::algorithm::replace_all( result, "  ", " " );
     return result;
  }

} // namespace fc

<commit_msg>Modify to_[u]int64, to_double to eval entire string #148<commit_after>#include <fc/string.hpp>
#include <fc/utility.hpp>
#include <fc/fwd_impl.hpp>
#include <fc/exception/exception.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

#include <string>
#include <sstream>
#include <iomanip>
#include <locale>
#include <limits>

/**
 *  Implemented with std::string for now.
 */

namespace fc  {
   class comma_numpunct : public std::numpunct<char>
   {
      protected:
         virtual char do_thousands_sep() const { return ','; }
         virtual std::string do_grouping() const { return "\03"; }
   };

  std::string to_pretty_string( int64_t value )
  {
     std::stringstream ss;
     ss.imbue( {std::locale(), new comma_numpunct} );
     ss << std::fixed << value;
     return ss.str();
  }

#ifdef USE_FC_STRING
  string::string(const char* s, int l) :my(s,l){ }
  string::string(){}
  string::string( const fc::string& c ):my(*c.my) { }
  string::string( string&& m ):my(fc::move(*m.my)) {}
  string::string( const char* c ):my(c){}
  string::string( const_iterator b, const_iterator e ):my(b,e){}
  string::string( const std::string& s ):my(s) {}
  string::string( std::string&& s ):my(fc::move(s)) {}
  string::~string() { }
  string::operator std::string&() { return *my; }
  string::operator const std::string&()const { return *my; }
  char* string::data() { return &my->front(); }

  string::iterator string::begin()            { return &(*this)[0]; }
  string::iterator string::end()              { return &(*this)[size()]; }
  string::const_iterator string::begin()const { return my->c_str(); }
  string::const_iterator string::end()const   { return my->c_str() + my->size(); }

  char&       string::operator[](size_t idx)      { return (*my)[idx]; }
  const char& string::operator[](size_t idx)const { return (*my)[idx]; }

  void       string::reserve(size_t r)           { my->reserve(r); }
  size_t   string::size()const                   { return my->size(); }
  size_t   string::find(char c, size_t p)const { return my->find(c,p); }
  size_t   string::find(const fc::string& str, size_t pos /* = 0 */) const { return my->find(str, pos); }
  size_t   string::find(const char* s, size_t pos /* = 0 */) const { return my->find(s,pos); }
  size_t   string::rfind(char c, size_t p)const { return my->rfind(c,p); }
  size_t   string::rfind(const char* c, size_t p)const { return my->rfind(c,p); }
  size_t   string::rfind(const fc::string& c, size_t p)const { return my->rfind(c,p); }
  size_t   string::find_first_of(const fc::string& str, size_t pos /* = 0 */) const { return my->find_first_of(str, pos); }
  size_t   string::find_first_of(const char* s, size_t pos /* = 0 */) const { return my->find_first_of(s, pos); }

  fc::string& string::replace(size_t pos,  size_t len,  const string& str) { my->replace(pos, len, str); return *this; }
  fc::string& string::replace(size_t pos,  size_t len,  const char* s) { my->replace(pos, len, s); return *this; }

  void       string::clear()                       { my->clear(); }
  void       string::resize( size_t s )          { my->resize(s); }

  fc::string string::substr( size_t start, size_t len )const { return my->substr(start,len); }
  const char* string::c_str()const                        { return my->c_str(); }

  bool    string::operator == ( const char* s )const   { return *my == s; }
  bool    string::operator == ( const string& s )const { return *my == *s.my; }
  bool    string::operator != ( const string& s )const { return *my != *s.my; }

  string& string::operator =( const string& c )          { *my = *c.my; return *this; }
  string& string::operator =( string&& c )               { *my = fc::move( *c.my ); return *this; }

  string& string::operator+=( const string& s )          { *my += *s.my; return *this; }
  string& string::operator+=( char c )                   { *my += c; return *this; }

  bool operator < ( const string& a, const string& b )   { return *a.my < *b.my; }
  string operator + ( const string& s, const string& c ) { return string(s) += c; }
  string operator + ( const string& s, char c ) 	 { return string(s) += c; }
#endif // USE_FC_STRING

  int64_t    to_int64( const fc::string& i )
  {
    try
    {
      return boost::lexical_cast<int64_t>(i.c_str(), i.size());
    }
    catch( const boost::bad_lexical_cast& e )
    {
      FC_THROW_EXCEPTION( parse_error_exception, "Couldn't parse int64_t" );
    }
    FC_RETHROW_EXCEPTIONS( warn, "${i} => int64_t", ("i",i) )
  }

  uint64_t   to_uint64( const fc::string& i )
  { try {
    try
    {
      return boost::lexical_cast<uint64_t>(i.c_str(), i.size());
    }
    catch( const boost::bad_lexical_cast& e )
    {
      FC_THROW_EXCEPTION( parse_error_exception, "Couldn't parse uint64_t" );
    }
    FC_RETHROW_EXCEPTIONS( warn, "${i} => uint64_t", ("i",i) )
  } FC_CAPTURE_AND_RETHROW( (i) ) }

  double     to_double( const fc::string& i)
  {
    try
    {
      return boost::lexical_cast<double>(i.c_str(), i.size());
    }
    catch( const boost::bad_lexical_cast& e )
    {
      FC_THROW_EXCEPTION( parse_error_exception, "Couldn't parse double" );
    }
    FC_RETHROW_EXCEPTIONS( warn, "${i} => double", ("i",i) )
  }

  fc::string to_string(double d)
  {
    // +2 is required to ensure that the double is rounded correctly when read back in.  http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
    std::stringstream ss;
    ss << std::setprecision(std::numeric_limits<double>::digits10 + 2) << std::fixed << d;
    return ss.str();
  }

  fc::string to_string( uint64_t d)
  {
    return boost::lexical_cast<std::string>(d);
  }

  fc::string to_string( int64_t d)
  {
    return boost::lexical_cast<std::string>(d);
  }
  fc::string to_string( uint16_t d)
  {
    return boost::lexical_cast<std::string>(d);
  }
  std::string trim( const std::string& s )
  {
      return boost::algorithm::trim_copy(s);
      /*
      std::string cpy(s);
      boost::algorithm::trim(cpy);
      return cpy;
      */
  }
  std::string to_lower( const std::string& s )
  {
     auto tmp = s;
     boost::algorithm::to_lower(tmp);
     return tmp;
  }
  string trim_and_normalize_spaces( const string& s )
  {
     string result = boost::algorithm::trim_copy( s );
     while( result.find( "  " ) != result.npos )
       boost::algorithm::replace_all( result, "  ", " " );
     return result;
  }

} // namespace fc

<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2017-2018 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "nodes/values/characteristic_curve/editor_window.h"
#include "elements/values/characteristic_curve.h"
#include "nodes/values/characteristic_curve.h"
#include "nodes/values/characteristic_curve/ui_editor_window.h"

#include <algorithm>

#include <QCheckBox>
#include <QComboBox>
#include <QDebug>
#include <QDoubleValidator>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QIntValidator>
#include <QItemDelegate>
#include <QKeyEvent>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QTabWidget>
#include <QTableWidget>
#include <QVBoxLayout>
#include <QtCharts/QLineSeries>

#include "ui/package_view.h"
//#include "nodes/values/characteristic_curve/axis_widget.h"
#include "nodes/values/characteristic_curve/axis.h"
//#include "nodes/values/characteristic_curve/series_widget.h"
#include "nodes/values/characteristic_curve/series.h"

template<class T>
class VPtr {
 public:
  static T *asPtr(QVariant v) { return reinterpret_cast<T *>(v.value<void *>()); }
  static QVariant asQVariant(T *ptr) { return qVariantFromValue(static_cast<void *>(ptr)); }
};

namespace spaghetti::nodes::values::characteristic_curve {

class Delegate : public QItemDelegate {
 public:
  Delegate(EditorWindow *const a_window)
    : QItemDelegate{ a_window }
    , m_window{ a_window }
  {
  }

  QWidget *createEditor(QWidget *a_parent, QStyleOptionViewItem const &a_option,
                        QModelIndex const &a_index) const override
  {
    (void)a_option;

    auto const lineEdit = new QLineEdit{ a_parent };

    EditorWindow::ValueType const TYPE{ (a_index.column() == 0 ? m_window->xValueType() : m_window->yValueType()) };
    QValidator *validator{};
    if (TYPE == EditorWindow::ValueType::eInt)
      validator = new QIntValidator;
    else
      validator = new QDoubleValidator;
    QLocale const LOCALE(QLocale::Language::English);
    validator->setLocale(LOCALE);
    lineEdit->setValidator(validator);
    return lineEdit;
  }

 private:
  EditorWindow *const m_window{};
};

EditorWindow::EditorWindow(CharacteristicCurve *const a_characteristicCurve)
  : QDialog{ a_characteristicCurve->packageView() }
  , m_ui{ new Ui::EditorWindow }
  , m_characteristicCurve{ a_characteristicCurve }
{
  m_ui->setupUi(this);

  m_ui->editor->setEditorWindow(this);
  QLocale const LOCALE{ QLocale::Language::English };
  m_ui->editor->setLocale(LOCALE);
  m_ui->seriesTable->setLocale(LOCALE);

  m_ui->xAxisName->setText(m_ui->editor->xName());
  m_ui->xAxisMajorTicks->setValue(m_ui->editor->xMajorTicks());
  m_ui->xAxisMinorTicks->setValue(m_ui->editor->xMinorTicks());
  m_ui->xAxisMinimum->setValue(m_ui->editor->xMinimum());
  m_ui->xAxisMaximum->setValue(m_ui->editor->xMaximum());

  connect(m_ui->xAxisName, &QLineEdit::textChanged, [this](QString const &a_name) {
    m_characteristicCurve->changeInputName(0, a_name);
    m_ui->editor->setXName(a_name);
  });

  connect(m_ui->xAxisMajorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setXMajorTicks(a_value); });

  connect(m_ui->xAxisMinorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setXMinorTicks(a_value); });

  connect(m_ui->xAxisMinimum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setXMinimum(a_value); });

  connect(m_ui->xAxisMaximum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setXMaximum(a_value); });

  connect(m_ui->yAxisName, &QLineEdit::textChanged, [this](QString const &a_name) {
    m_characteristicCurve->changeOutputName(0, a_name);
    m_ui->editor->setYName(a_name);
  });

  connect(m_ui->yAxisMajorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setYMajorTicks(a_value); });

  connect(m_ui->yAxisMinorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setYMinorTicks(a_value); });

  connect(m_ui->yAxisMinimum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setYMinimum(a_value); });

  connect(m_ui->yAxisMaximum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setYMaximum(a_value); });

  connect(m_ui->seriesTable, &QTableWidget::cellChanged, [this](int a_row, int a_column) {
    auto const xItem = m_ui->seriesTable->item(a_row, 0);
    auto const yItem = m_ui->seriesTable->item(a_row, 1);
    if (!xItem || !yItem) return;

    auto const X = xItem->data(Qt::DisplayRole).toDouble();
    auto const Y = yItem->data(Qt::DisplayRole).toDouble();

    m_ui->editor->changePoint(a_row, QPointF{ X, Y });
  });
  connect(m_ui->live, &QCheckBox::stateChanged, [this](int const a_state) { setLive(a_state == 2); });
  connect(m_ui->save, &QPushButton::clicked, [this]() { synchronizeToNode(); });
  connect(m_ui->load, &QPushButton::clicked, [this]() { synchronizeFromNode(); });

  setLive(false);
}

EditorWindow::~EditorWindow()
{
  delete m_ui;
}

void EditorWindow::showEvent(QShowEvent *a_event)
{
  //  qDebug() << Q_FUNC_INFO;

  static bool first{ true };
  if (!first) QWidget::showEvent(a_event);

  first = true;

  m_ui->editor->updatePoints();
}

void EditorWindow::resizeEvent(QResizeEvent *a_event)
{
  //  qDebug() << Q_FUNC_INFO << a_event;
  QWidget::resizeEvent(a_event);
}

void EditorWindow::synchronizeToNode()
{
  if (!m_characteristicCurve->element()) return;

  auto const editor = m_ui->editor;
  auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());

  element->setXMajorTicks(editor->xMajorTicks());
  element->setXMinorTicks(editor->xMinorTicks());
  element->setXMinimum(static_cast<float>(editor->xMinimum()));
  element->setXMaximum(static_cast<float>(editor->xMaximum()));

  element->setYMajorTicks(editor->yMajorTicks());
  element->setYMinorTicks(editor->yMinorTicks());
  element->setYMinimum(static_cast<float>(editor->yMinimum()));
  element->setYMaximum(static_cast<float>(editor->yMaximum()));

  auto &series = element->series();
  auto const nodeSeries = m_characteristicCurve->series();
  auto const editorSeries = editor->series();
  auto const SIZE = editorSeries->count();

  series.clear();
  nodeSeries->clear();
  for (int i = 0; i < SIZE; ++i) {
    auto const &point = editorSeries->at(i);
    series.push_back(Element::vec2f{ static_cast<float>(point.x()), static_cast<float>(point.y()) });
    nodeSeries->append(point);
  }
}

void EditorWindow::synchronizeFromNode()
{
  auto const editor = m_ui->editor;
  auto const node = m_characteristicCurve;
  auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());

  editor->setXName(node->inputs()[0]->name());
  editor->setXMajorTicks(element->xMajorTicks());
  editor->setXMinorTicks(element->xMinorTicks());
  editor->setXMinimum(static_cast<qreal>(element->xMinimum()));
  editor->setXMaximum(static_cast<qreal>(element->xMaximum()));
  m_ui->xAxisName->setText(node->inputs()[0]->name());
  m_ui->xAxisMajorTicks->setValue(element->xMajorTicks());
  m_ui->xAxisMinorTicks->setValue(element->xMinorTicks());
  m_ui->xAxisMinimum->setValue(static_cast<qreal>(element->xMinimum()));
  m_ui->xAxisMaximum->setValue(static_cast<qreal>(element->xMaximum()));

  editor->setYName(node->outputs()[0]->name());
  editor->setYMajorTicks(element->yMajorTicks());
  editor->setYMinorTicks(element->yMinorTicks());
  editor->setYMinimum(static_cast<qreal>(element->yMinimum()));
  editor->setYMaximum(static_cast<qreal>(element->yMaximum()));
  m_ui->yAxisName->setText(node->outputs()[0]->name());
  m_ui->yAxisMajorTicks->setValue(element->yMajorTicks());
  m_ui->yAxisMinorTicks->setValue(element->yMinorTicks());
  m_ui->yAxisMinimum->setValue(static_cast<qreal>(element->yMinimum()));
  m_ui->yAxisMaximum->setValue(static_cast<qreal>(element->yMaximum()));

  m_xValueType = element->inputs()[0].type == Element::ValueType::eInt ? ValueType::eInt : ValueType::eDouble;
  m_yValueType = element->outputs()[0].type == Element::ValueType::eInt ? ValueType::eInt : ValueType::eDouble;

  recreateSeries();
}

void EditorWindow::setValue(qreal const a_value)
{
  m_ui->editor->setX(a_value);
}

void EditorWindow::setLive(bool const a_live)
{
  m_live = a_live;
  m_ui->load->setDisabled(a_live);
  m_ui->save->setDisabled(a_live);
  if (a_live) synchronizeToNode();
}

void EditorWindow::addPoint(int const a_index, QPointF const a_point)
{
  auto const seriesTable = m_ui->seriesTable;

  auto const BLOCKED{ seriesTable->blockSignals(true) };

  seriesTable->insertRow(a_index);

  auto const xItem = new QTableWidgetItem;
  xItem->setData(Qt::DisplayRole, a_point.x());
  if (a_index == 0 || a_index == seriesTable->rowCount() - 1) xItem->setFlags(xItem->flags() & ~Qt::ItemIsEditable);
  seriesTable->setItem(a_index, 0, xItem);
  auto const yItem = new QTableWidgetItem;
  yItem->setData(Qt::DisplayRole, a_point.y());
  seriesTable->setItem(a_index, 1, yItem);

  seriesTable->blockSignals(BLOCKED);

  if (m_live) {
    auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
    auto &series = element->series();
    auto const nodeSeries = m_characteristicCurve->series();
    series.insert(std::begin(series) + a_index,
                  Element::vec2f{ static_cast<float>(a_point.x()), static_cast<float>(a_point.y()) });
    nodeSeries->insert(a_index, a_point);
  }
}

void EditorWindow::changePoint(int const a_index, QPointF const a_point)
{
  auto const xItem = m_ui->seriesTable->item(a_index, 0);
  xItem->setData(Qt::DisplayRole, a_point.x());
  auto const yItem = m_ui->seriesTable->item(a_index, 1);
  yItem->setData(Qt::DisplayRole, a_point.y());

  if (m_live) {
    auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
    auto &series = element->series();
    auto const nodeSeries = m_characteristicCurve->series();
    series[a_index].x = static_cast<float>(a_point.x());
    series[a_index].y = static_cast<float>(a_point.y());
    nodeSeries->replace(a_index, a_point);
  }
}

void EditorWindow::removePoint(int const a_index)
{
  m_ui->seriesTable->removeRow(a_index);

  if (m_live) {
    auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
    auto &series = element->series();
    auto const nodeSeries = m_characteristicCurve->series();
    series.erase(std::begin(series) + a_index);
    nodeSeries->remove(a_index);
  }
}

void EditorWindow::recreateSeries()
{
  auto const editor = m_ui->editor;
  auto const editorSeries = editor->series();
  auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
  auto const seriesTable = m_ui->seriesTable;
  auto &series = element->series();

  editorSeries->clear();
  seriesTable->setRowCount(0);

  seriesTable->setItemDelegate(new Delegate{ this });

  for (auto &point : series) {
    editorSeries->append(static_cast<qreal>(point.x), static_cast<qreal>(point.y));

    auto const ROW = seriesTable->rowCount();
    addPoint(ROW, QPointF{ static_cast<qreal>(point.x), static_cast<qreal>(point.y) });
  }

  editor->updatePoints();
}

void EditorWindow::setXValueType(ValueType const a_type)
{
  m_xValueType = a_type;
}

void EditorWindow::setYValueType(ValueType const a_type)
{
  m_yValueType = a_type;
}

} // namespace spaghetti::nodes::values::characteristic_curve
<commit_msg>Fix warning<commit_after>// MIT License
//
// Copyright (c) 2017-2018 Artur Wyszyński, aljen at hitomi dot pl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "nodes/values/characteristic_curve/editor_window.h"
#include "elements/values/characteristic_curve.h"
#include "nodes/values/characteristic_curve.h"
#include "nodes/values/characteristic_curve/ui_editor_window.h"

#include <algorithm>

#include <QCheckBox>
#include <QComboBox>
#include <QDebug>
#include <QDoubleValidator>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QIntValidator>
#include <QItemDelegate>
#include <QKeyEvent>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QTabWidget>
#include <QTableWidget>
#include <QVBoxLayout>
#include <QtCharts/QLineSeries>

#include "ui/package_view.h"
//#include "nodes/values/characteristic_curve/axis_widget.h"
#include "nodes/values/characteristic_curve/axis.h"
//#include "nodes/values/characteristic_curve/series_widget.h"
#include "nodes/values/characteristic_curve/series.h"

template<class T>
class VPtr {
 public:
  static T *asPtr(QVariant v) { return reinterpret_cast<T *>(v.value<void *>()); }
  static QVariant asQVariant(T *ptr) { return qVariantFromValue(static_cast<void *>(ptr)); }
};

namespace spaghetti::nodes::values::characteristic_curve {

class Delegate : public QItemDelegate {
 public:
  Delegate(EditorWindow *const a_window)
    : QItemDelegate{ a_window }
    , m_window{ a_window }
  {
  }

  QWidget *createEditor(QWidget *a_parent, QStyleOptionViewItem const &a_option,
                        QModelIndex const &a_index) const override
  {
    (void)a_option;

    auto const lineEdit = new QLineEdit{ a_parent };

    EditorWindow::ValueType const TYPE{ (a_index.column() == 0 ? m_window->xValueType() : m_window->yValueType()) };
    QValidator *validator{};
    if (TYPE == EditorWindow::ValueType::eInt)
      validator = new QIntValidator;
    else
      validator = new QDoubleValidator;
    QLocale const LOCALE(QLocale::Language::English);
    validator->setLocale(LOCALE);
    lineEdit->setValidator(validator);
    return lineEdit;
  }

 private:
  EditorWindow *const m_window{};
};

EditorWindow::EditorWindow(CharacteristicCurve *const a_characteristicCurve)
  : QDialog{ a_characteristicCurve->packageView() }
  , m_ui{ new Ui::EditorWindow }
  , m_characteristicCurve{ a_characteristicCurve }
{
  m_ui->setupUi(this);

  m_ui->editor->setEditorWindow(this);
  QLocale const LOCALE{ QLocale::Language::English };
  m_ui->editor->setLocale(LOCALE);
  m_ui->seriesTable->setLocale(LOCALE);

  m_ui->xAxisName->setText(m_ui->editor->xName());
  m_ui->xAxisMajorTicks->setValue(m_ui->editor->xMajorTicks());
  m_ui->xAxisMinorTicks->setValue(m_ui->editor->xMinorTicks());
  m_ui->xAxisMinimum->setValue(m_ui->editor->xMinimum());
  m_ui->xAxisMaximum->setValue(m_ui->editor->xMaximum());

  connect(m_ui->xAxisName, &QLineEdit::textChanged, [this](QString const &a_name) {
    m_characteristicCurve->changeInputName(0, a_name);
    m_ui->editor->setXName(a_name);
  });

  connect(m_ui->xAxisMajorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setXMajorTicks(a_value); });

  connect(m_ui->xAxisMinorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setXMinorTicks(a_value); });

  connect(m_ui->xAxisMinimum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setXMinimum(a_value); });

  connect(m_ui->xAxisMaximum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setXMaximum(a_value); });

  connect(m_ui->yAxisName, &QLineEdit::textChanged, [this](QString const &a_name) {
    m_characteristicCurve->changeOutputName(0, a_name);
    m_ui->editor->setYName(a_name);
  });

  connect(m_ui->yAxisMajorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setYMajorTicks(a_value); });

  connect(m_ui->yAxisMinorTicks, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
          [this](int a_value) { m_ui->editor->setYMinorTicks(a_value); });

  connect(m_ui->yAxisMinimum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setYMinimum(a_value); });

  connect(m_ui->yAxisMaximum, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
          [this](qreal a_value) { m_ui->editor->setYMaximum(a_value); });

  connect(m_ui->seriesTable, &QTableWidget::cellChanged, [this](int a_row, int) {
    auto const xItem = m_ui->seriesTable->item(a_row, 0);
    auto const yItem = m_ui->seriesTable->item(a_row, 1);
    if (!xItem || !yItem) return;

    auto const X = xItem->data(Qt::DisplayRole).toDouble();
    auto const Y = yItem->data(Qt::DisplayRole).toDouble();

    m_ui->editor->changePoint(a_row, QPointF{ X, Y });
  });
  connect(m_ui->live, &QCheckBox::stateChanged, [this](int const a_state) { setLive(a_state == 2); });
  connect(m_ui->save, &QPushButton::clicked, [this]() { synchronizeToNode(); });
  connect(m_ui->load, &QPushButton::clicked, [this]() { synchronizeFromNode(); });

  setLive(false);
}

EditorWindow::~EditorWindow()
{
  delete m_ui;
}

void EditorWindow::showEvent(QShowEvent *a_event)
{
  //  qDebug() << Q_FUNC_INFO;

  static bool first{ true };
  if (!first) QWidget::showEvent(a_event);

  first = true;

  m_ui->editor->updatePoints();
}

void EditorWindow::resizeEvent(QResizeEvent *a_event)
{
  //  qDebug() << Q_FUNC_INFO << a_event;
  QWidget::resizeEvent(a_event);
}

void EditorWindow::synchronizeToNode()
{
  if (!m_characteristicCurve->element()) return;

  auto const editor = m_ui->editor;
  auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());

  element->setXMajorTicks(editor->xMajorTicks());
  element->setXMinorTicks(editor->xMinorTicks());
  element->setXMinimum(static_cast<float>(editor->xMinimum()));
  element->setXMaximum(static_cast<float>(editor->xMaximum()));

  element->setYMajorTicks(editor->yMajorTicks());
  element->setYMinorTicks(editor->yMinorTicks());
  element->setYMinimum(static_cast<float>(editor->yMinimum()));
  element->setYMaximum(static_cast<float>(editor->yMaximum()));

  auto &series = element->series();
  auto const nodeSeries = m_characteristicCurve->series();
  auto const editorSeries = editor->series();
  auto const SIZE = editorSeries->count();

  series.clear();
  nodeSeries->clear();
  for (int i = 0; i < SIZE; ++i) {
    auto const &point = editorSeries->at(i);
    series.push_back(Element::vec2f{ static_cast<float>(point.x()), static_cast<float>(point.y()) });
    nodeSeries->append(point);
  }
}

void EditorWindow::synchronizeFromNode()
{
  auto const editor = m_ui->editor;
  auto const node = m_characteristicCurve;
  auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());

  editor->setXName(node->inputs()[0]->name());
  editor->setXMajorTicks(element->xMajorTicks());
  editor->setXMinorTicks(element->xMinorTicks());
  editor->setXMinimum(static_cast<qreal>(element->xMinimum()));
  editor->setXMaximum(static_cast<qreal>(element->xMaximum()));
  m_ui->xAxisName->setText(node->inputs()[0]->name());
  m_ui->xAxisMajorTicks->setValue(element->xMajorTicks());
  m_ui->xAxisMinorTicks->setValue(element->xMinorTicks());
  m_ui->xAxisMinimum->setValue(static_cast<qreal>(element->xMinimum()));
  m_ui->xAxisMaximum->setValue(static_cast<qreal>(element->xMaximum()));

  editor->setYName(node->outputs()[0]->name());
  editor->setYMajorTicks(element->yMajorTicks());
  editor->setYMinorTicks(element->yMinorTicks());
  editor->setYMinimum(static_cast<qreal>(element->yMinimum()));
  editor->setYMaximum(static_cast<qreal>(element->yMaximum()));
  m_ui->yAxisName->setText(node->outputs()[0]->name());
  m_ui->yAxisMajorTicks->setValue(element->yMajorTicks());
  m_ui->yAxisMinorTicks->setValue(element->yMinorTicks());
  m_ui->yAxisMinimum->setValue(static_cast<qreal>(element->yMinimum()));
  m_ui->yAxisMaximum->setValue(static_cast<qreal>(element->yMaximum()));

  m_xValueType = element->inputs()[0].type == Element::ValueType::eInt ? ValueType::eInt : ValueType::eDouble;
  m_yValueType = element->outputs()[0].type == Element::ValueType::eInt ? ValueType::eInt : ValueType::eDouble;

  recreateSeries();
}

void EditorWindow::setValue(qreal const a_value)
{
  m_ui->editor->setX(a_value);
}

void EditorWindow::setLive(bool const a_live)
{
  m_live = a_live;
  m_ui->load->setDisabled(a_live);
  m_ui->save->setDisabled(a_live);
  if (a_live) synchronizeToNode();
}

void EditorWindow::addPoint(int const a_index, QPointF const a_point)
{
  auto const seriesTable = m_ui->seriesTable;

  auto const BLOCKED{ seriesTable->blockSignals(true) };

  seriesTable->insertRow(a_index);

  auto const xItem = new QTableWidgetItem;
  xItem->setData(Qt::DisplayRole, a_point.x());
  if (a_index == 0 || a_index == seriesTable->rowCount() - 1) xItem->setFlags(xItem->flags() & ~Qt::ItemIsEditable);
  seriesTable->setItem(a_index, 0, xItem);
  auto const yItem = new QTableWidgetItem;
  yItem->setData(Qt::DisplayRole, a_point.y());
  seriesTable->setItem(a_index, 1, yItem);

  seriesTable->blockSignals(BLOCKED);

  if (m_live) {
    auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
    auto &series = element->series();
    auto const nodeSeries = m_characteristicCurve->series();
    series.insert(std::begin(series) + a_index,
                  Element::vec2f{ static_cast<float>(a_point.x()), static_cast<float>(a_point.y()) });
    nodeSeries->insert(a_index, a_point);
  }
}

void EditorWindow::changePoint(int const a_index, QPointF const a_point)
{
  auto const xItem = m_ui->seriesTable->item(a_index, 0);
  xItem->setData(Qt::DisplayRole, a_point.x());
  auto const yItem = m_ui->seriesTable->item(a_index, 1);
  yItem->setData(Qt::DisplayRole, a_point.y());

  if (m_live) {
    auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
    auto &series = element->series();
    auto const nodeSeries = m_characteristicCurve->series();
    series[a_index].x = static_cast<float>(a_point.x());
    series[a_index].y = static_cast<float>(a_point.y());
    nodeSeries->replace(a_index, a_point);
  }
}

void EditorWindow::removePoint(int const a_index)
{
  m_ui->seriesTable->removeRow(a_index);

  if (m_live) {
    auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
    auto &series = element->series();
    auto const nodeSeries = m_characteristicCurve->series();
    series.erase(std::begin(series) + a_index);
    nodeSeries->remove(a_index);
  }
}

void EditorWindow::recreateSeries()
{
  auto const editor = m_ui->editor;
  auto const editorSeries = editor->series();
  auto const element = static_cast<elements::values::CharacteristicCurve *>(m_characteristicCurve->element());
  auto const seriesTable = m_ui->seriesTable;
  auto &series = element->series();

  editorSeries->clear();
  seriesTable->setRowCount(0);

  seriesTable->setItemDelegate(new Delegate{ this });

  for (auto &point : series) {
    editorSeries->append(static_cast<qreal>(point.x), static_cast<qreal>(point.y));

    auto const ROW = seriesTable->rowCount();
    addPoint(ROW, QPointF{ static_cast<qreal>(point.x), static_cast<qreal>(point.y) });
  }

  editor->updatePoints();
}

void EditorWindow::setXValueType(ValueType const a_type)
{
  m_xValueType = a_type;
}

void EditorWindow::setYValueType(ValueType const a_type)
{
  m_yValueType = a_type;
}

} // namespace spaghetti::nodes::values::characteristic_curve
<|endoftext|>


<commit_before>// Copyright (c) 2015 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "image_describer_akaze.hpp"

namespace openMVG {
namespace features {

std::unique_ptr<AKAZE_Image_describer_SURF::Regions_type>
AKAZE_Image_describer_SURF::Describe_AKAZE_SURF
(
  const image::Image<unsigned char>& image,
  const image::Image<unsigned char>* mask
)
{
  params_.options_.fDesc_factor = GetfDescFactor();

  AKAZE akaze(image, params_.options_);
  akaze.Compute_AKAZEScaleSpace();
  std::vector<AKAZEKeypoint> kpts;
  kpts.reserve(5000);
  akaze.Feature_Detection(kpts);
  akaze.Do_Subpixel_Refinement(kpts);

  // Feature masking (remove keypoints if they are masked)
  kpts.erase(std::remove_if(kpts.begin(),
                            kpts.end(),
                            [&](const AKAZEKeypoint & pt)
                            {
                              if (mask) return (*mask)(pt.y, pt.x) == 0;
                            }),
             kpts.end());

  // will be automatically deleted if something goes wrong
  auto regions = std::unique_ptr<Regions_type>(new Regions_type);
  regions->Features().resize(kpts.size());
  regions->Descriptors().resize(kpts.size());

  #ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel for
  #endif
  for (int i = 0; i<static_cast<int>(kpts.size()); ++i) {
    AKAZEKeypoint ptAkaze = kpts[i];

    const TEvolution& cur_slice = akaze.getSlices()[ptAkaze.class_id];

    if (bOrientation_)
      akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly);
    else
      ptAkaze.angle = 0.0f;

    regions->Features()[i] =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle);

    ComputeMSURFDescriptor(cur_slice.Lx, cur_slice.Ly, ptAkaze.octave,
      regions->Features()[i],
      regions->Descriptors()[i]);
  }
  return regions;
}

std::unique_ptr<AKAZE_Image_describer_LIOP::Regions_type>
AKAZE_Image_describer_LIOP::Describe_AKAZE_LIOP
(
  const image::Image<unsigned char>& image,
  const image::Image<unsigned char>* mask
)
{
  params_.options_.fDesc_factor = GetfDescFactor();

  AKAZE akaze(image, params_.options_);
  akaze.Compute_AKAZEScaleSpace();
  std::vector<AKAZEKeypoint> kpts;
  kpts.reserve(5000);
  akaze.Feature_Detection(kpts);
  akaze.Do_Subpixel_Refinement(kpts);

  // Feature masking (remove keypoints if they are masked)
  kpts.erase(std::remove_if(kpts.begin(),
                            kpts.end(),
                            [&](const AKAZEKeypoint & pt)
                            {
                              if (mask) return (*mask)(pt.y, pt.x) == 0;
                            }),
             kpts.end());

  // will be automatically deleted if something goes wrong
  auto regions = std::unique_ptr<Regions_type>(new Regions_type);
  regions->Features().resize(kpts.size());
  regions->Descriptors().resize(kpts.size());

  // Init LIOP extractor
  LIOP::Liop_Descriptor_Extractor liop_extractor;

  #ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel for
  #endif
  for (int i = 0; i<static_cast<int>(kpts.size()); ++i) {
    AKAZEKeypoint ptAkaze = kpts[i];

    const TEvolution& cur_slice = akaze.getSlices()[ptAkaze.class_id];

    if (bOrientation_)
      akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly);
    else
      ptAkaze.angle = 0.0f;

    regions->Features()[i] =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle);

    // Compute LIOP descriptor (do not need rotation computation, since
    //  LIOP descriptor is rotation invariant).
    // Rescale for LIOP patch extraction
    const SIOPointFeature fp =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size/2.0, ptAkaze.angle);

    float desc[144];
    liop_extractor.extract(image, fp, desc);
    for (int j = 0; j<144; ++j)
      regions->Descriptors()[i][j] =
        static_cast<unsigned char>(desc[j]*255.f+.5f);
  }
  return regions;
}

std::unique_ptr<AKAZE_Image_describer_MLDB::Regions_type>
AKAZE_Image_describer_MLDB::Describe_AKAZE_MLDB
(
  const image::Image<unsigned char>& image,
  const image::Image<unsigned char>* mask
)
{
  params_.options_.fDesc_factor = GetfDescFactor();

  AKAZE akaze(image, params_.options_);
  akaze.Compute_AKAZEScaleSpace();
  std::vector<AKAZEKeypoint> kpts;
  kpts.reserve(5000);
  akaze.Feature_Detection(kpts);
  akaze.Do_Subpixel_Refinement(kpts);

  // Feature masking (remove keypoints if they are masked)
  kpts.erase(std::remove_if(kpts.begin(),
                            kpts.end(),
                            [&](const AKAZEKeypoint & pt)
                            {
                              if (mask) return (*mask)(pt.y, pt.x) == 0;
                            }),
             kpts.end());

  // will be automatically deleted if something goes wrong
  auto regions = std::unique_ptr<Regions_type>(new Regions_type);
  regions->Features().resize(kpts.size());
  regions->Descriptors().resize(kpts.size());

  #ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel for
  #endif
  for (int i = 0; i<static_cast<int>(kpts.size()); ++i) {
    AKAZEKeypoint ptAkaze = kpts[i];

    const TEvolution& cur_slice = akaze.getSlices()[ptAkaze.class_id];

    if (bOrientation_)
      akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly);
    else
      ptAkaze.angle = 0.0f;

    regions->Features()[i] =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle);

    // Compute MLDB descriptor
    Descriptor<bool, 486> desc;
    ComputeMLDBDescriptor(cur_slice.cur, cur_slice.Lx, cur_slice.Ly,
      ptAkaze.octave, regions->Features()[i], desc);
    // convert the bool vector to the binary unsigned char array
    unsigned char* ptr = reinterpret_cast<unsigned char*>(&regions->Descriptors()[i]);
    memset(ptr, 0, regions->DescriptorLength()*sizeof(unsigned char));
    // For each byte
    for (int j = 0; j<std::ceil(486./8.); ++j, ++ptr)
    {
      // set the corresponding 8bits to the good values
      for (int iBit = 0; iBit<8 && j*8+iBit<486; ++iBit)
      {
        *ptr |= desc[j*8+iBit] << iBit;
      }
    }
  }
  return regions;
}

// static
std::unique_ptr<AKAZE_Image_describer> AKAZE_Image_describer::create
(
  const AKAZE_Image_describer::Params& params,
  bool orientation
)
{
  switch (params.eAkazeDescriptor_) {
  case AKAZE_MSURF:
    return std::unique_ptr<AKAZE_Image_describer>
        (new AKAZE_Image_describer_SURF(params, orientation));
  case AKAZE_LIOP:
    return std::unique_ptr<AKAZE_Image_describer>
        (new AKAZE_Image_describer_LIOP(params, orientation));
  case AKAZE_MLDB:
    return std::unique_ptr<AKAZE_Image_describer>
        (new AKAZE_Image_describer_MLDB(params, orientation));
  default:
    return nullptr;
  }
}

} // namespace features
} // namespace openMVG
<commit_msg>[features] AKAZE feature extraction -> mask filtering bug #999<commit_after>// Copyright (c) 2015 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "image_describer_akaze.hpp"

namespace openMVG {
namespace features {

std::unique_ptr<AKAZE_Image_describer_SURF::Regions_type>
AKAZE_Image_describer_SURF::Describe_AKAZE_SURF
(
  const image::Image<unsigned char>& image,
  const image::Image<unsigned char>* mask
)
{
  params_.options_.fDesc_factor = GetfDescFactor();

  AKAZE akaze(image, params_.options_);
  akaze.Compute_AKAZEScaleSpace();
  std::vector<AKAZEKeypoint> kpts;
  kpts.reserve(5000);
  akaze.Feature_Detection(kpts);
  akaze.Do_Subpixel_Refinement(kpts);

  // Feature masking (remove keypoints if they are masked)
  kpts.erase(std::remove_if(kpts.begin(),
                            kpts.end(),
                            [&](const AKAZEKeypoint & pt)
                            {
                              if (mask) return (*mask)(pt.y, pt.x) == 0;
                              else return false;
                            }),
             kpts.end());

  // will be automatically deleted if something goes wrong
  auto regions = std::unique_ptr<Regions_type>(new Regions_type);
  regions->Features().resize(kpts.size());
  regions->Descriptors().resize(kpts.size());

  #ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel for
  #endif
  for (int i = 0; i<static_cast<int>(kpts.size()); ++i) {
    AKAZEKeypoint ptAkaze = kpts[i];

    const TEvolution& cur_slice = akaze.getSlices()[ptAkaze.class_id];

    if (bOrientation_)
      akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly);
    else
      ptAkaze.angle = 0.0f;

    regions->Features()[i] =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle);

    ComputeMSURFDescriptor(cur_slice.Lx, cur_slice.Ly, ptAkaze.octave,
      regions->Features()[i],
      regions->Descriptors()[i]);
  }
  return regions;
}

std::unique_ptr<AKAZE_Image_describer_LIOP::Regions_type>
AKAZE_Image_describer_LIOP::Describe_AKAZE_LIOP
(
  const image::Image<unsigned char>& image,
  const image::Image<unsigned char>* mask
)
{
  params_.options_.fDesc_factor = GetfDescFactor();

  AKAZE akaze(image, params_.options_);
  akaze.Compute_AKAZEScaleSpace();
  std::vector<AKAZEKeypoint> kpts;
  kpts.reserve(5000);
  akaze.Feature_Detection(kpts);
  akaze.Do_Subpixel_Refinement(kpts);

  // Feature masking (remove keypoints if they are masked)
  kpts.erase(std::remove_if(kpts.begin(),
                            kpts.end(),
                            [&](const AKAZEKeypoint & pt)
                            {
                              if (mask) return (*mask)(pt.y, pt.x) == 0;
                              else return false;
                            }),
             kpts.end());

  // will be automatically deleted if something goes wrong
  auto regions = std::unique_ptr<Regions_type>(new Regions_type);
  regions->Features().resize(kpts.size());
  regions->Descriptors().resize(kpts.size());

  // Init LIOP extractor
  LIOP::Liop_Descriptor_Extractor liop_extractor;

  #ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel for
  #endif
  for (int i = 0; i<static_cast<int>(kpts.size()); ++i) {
    AKAZEKeypoint ptAkaze = kpts[i];

    const TEvolution& cur_slice = akaze.getSlices()[ptAkaze.class_id];

    if (bOrientation_)
      akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly);
    else
      ptAkaze.angle = 0.0f;

    regions->Features()[i] =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle);

    // Compute LIOP descriptor (do not need rotation computation, since
    //  LIOP descriptor is rotation invariant).
    // Rescale for LIOP patch extraction
    const SIOPointFeature fp =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size/2.0, ptAkaze.angle);

    float desc[144];
    liop_extractor.extract(image, fp, desc);
    for (int j = 0; j<144; ++j)
      regions->Descriptors()[i][j] =
        static_cast<unsigned char>(desc[j]*255.f+.5f);
  }
  return regions;
}

std::unique_ptr<AKAZE_Image_describer_MLDB::Regions_type>
AKAZE_Image_describer_MLDB::Describe_AKAZE_MLDB
(
  const image::Image<unsigned char>& image,
  const image::Image<unsigned char>* mask
)
{
  params_.options_.fDesc_factor = GetfDescFactor();

  AKAZE akaze(image, params_.options_);
  akaze.Compute_AKAZEScaleSpace();
  std::vector<AKAZEKeypoint> kpts;
  kpts.reserve(5000);
  akaze.Feature_Detection(kpts);
  akaze.Do_Subpixel_Refinement(kpts);

  // Feature masking (remove keypoints if they are masked)
  kpts.erase(std::remove_if(kpts.begin(),
                            kpts.end(),
                            [&](const AKAZEKeypoint & pt)
                            {
                              if (mask) return (*mask)(pt.y, pt.x) == 0;
                              else return false;
                            }),
             kpts.end());

  // will be automatically deleted if something goes wrong
  auto regions = std::unique_ptr<Regions_type>(new Regions_type);
  regions->Features().resize(kpts.size());
  regions->Descriptors().resize(kpts.size());

  #ifdef OPENMVG_USE_OPENMP
  #pragma omp parallel for
  #endif
  for (int i = 0; i<static_cast<int>(kpts.size()); ++i) {
    AKAZEKeypoint ptAkaze = kpts[i];

    const TEvolution& cur_slice = akaze.getSlices()[ptAkaze.class_id];

    if (bOrientation_)
      akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly);
    else
      ptAkaze.angle = 0.0f;

    regions->Features()[i] =
      SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle);

    // Compute MLDB descriptor
    Descriptor<bool, 486> desc;
    ComputeMLDBDescriptor(cur_slice.cur, cur_slice.Lx, cur_slice.Ly,
      ptAkaze.octave, regions->Features()[i], desc);
    // convert the bool vector to the binary unsigned char array
    unsigned char* ptr = reinterpret_cast<unsigned char*>(&regions->Descriptors()[i]);
    memset(ptr, 0, regions->DescriptorLength()*sizeof(unsigned char));
    // For each byte
    for (int j = 0; j<std::ceil(486./8.); ++j, ++ptr)
    {
      // set the corresponding 8bits to the good values
      for (int iBit = 0; iBit<8 && j*8+iBit<486; ++iBit)
      {
        *ptr |= desc[j*8+iBit] << iBit;
      }
    }
  }
  return regions;
}

// static
std::unique_ptr<AKAZE_Image_describer> AKAZE_Image_describer::create
(
  const AKAZE_Image_describer::Params& params,
  bool orientation
)
{
  switch (params.eAkazeDescriptor_) {
  case AKAZE_MSURF:
    return std::unique_ptr<AKAZE_Image_describer>
        (new AKAZE_Image_describer_SURF(params, orientation));
  case AKAZE_LIOP:
    return std::unique_ptr<AKAZE_Image_describer>
        (new AKAZE_Image_describer_LIOP(params, orientation));
  case AKAZE_MLDB:
    return std::unique_ptr<AKAZE_Image_describer>
        (new AKAZE_Image_describer_MLDB(params, orientation));
  default:
    return nullptr;
  }
}

} // namespace features
} // namespace openMVG
<|endoftext|>


<commit_before>/*
 Copyright 2015 Nervana Systems 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 "api_pversion.hpp"

extern "C" {

extern const char* get_error_message() {
    return last_error_message.c_str();
}

extern void* start(const char* loaderConfigString,
                   PyObject* pbackend
                   ) {
    static_assert(sizeof(int) == 4, "int is not 4 bytes");
    try {

        PyLoader* loader = new PyLoader(loaderConfigString, pbackend);

        int result = loader->start();
        if (result != 0) {
            std::stringstream ss;
            ss << "Could not start data loader. Error " << result;
            last_error_message = ss.str();
            delete loader;

            Py_INCREF(Py_None);
            return Py_None;
        }
        return reinterpret_cast<void*>(loader);
    } catch(std::exception& ex) {
        last_error_message = ex.what();

        Py_INCREF(Py_None);
        return Py_None;
    }
}

extern int error() {
    try {
        throw std::runtime_error("abc error");
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

extern PyObject* next(PyLoader* loader, int bufIdx) {
    try {
        return loader->next(bufIdx);
    } catch(std::exception& ex) {
        last_error_message = ex.what();

        Py_INCREF(Py_None);
        return Py_None;
    }
}

extern int itemCount(PyLoader* loader) {
    try {
        return loader->itemCount();
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

extern int reset(PyLoader* loader) {
    try {
        return loader->reset();
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

extern int stop(PyLoader* loader) {
    try {
        loader->stop();
        delete loader;
        return 0;
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

}
<commit_msg>because the return type of loaderlib.start is ct.c_void_p, returning 0 gets translated into a None by ctypes, so return that instead of a pointer to the None object<commit_after>/*
 Copyright 2015 Nervana Systems 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 "api_pversion.hpp"

extern "C" {

extern const char* get_error_message() {
    return last_error_message.c_str();
}

extern void* start(const char* loaderConfigString,
                   PyObject* pbackend
                   ) {
    static_assert(sizeof(int) == 4, "int is not 4 bytes");
    try {

        PyLoader* loader = new PyLoader(loaderConfigString, pbackend);

        int result = loader->start();
        if (result != 0) {
            std::stringstream ss;
            ss << "Could not start data loader. Error " << result;
            last_error_message = ss.str();
            delete loader;

            return 0;
        }
        return reinterpret_cast<void*>(loader);
    } catch(std::exception& ex) {
        last_error_message = ex.what();

        return 0;
    }
}

extern int error() {
    try {
        throw std::runtime_error("abc error");
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

extern PyObject* next(PyLoader* loader, int bufIdx) {
    try {
        return loader->next(bufIdx);
    } catch(std::exception& ex) {
        last_error_message = ex.what();

        Py_INCREF(Py_None);
        return Py_None;
    }
}

extern int itemCount(PyLoader* loader) {
    try {
        return loader->itemCount();
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

extern int reset(PyLoader* loader) {
    try {
        return loader->reset();
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

extern int stop(PyLoader* loader) {
    try {
        loader->stop();
        delete loader;
        return 0;
    } catch(std::exception& ex) {
        last_error_message = ex.what();
        return -1;
    }
}

}
<|endoftext|>


<commit_before>// Copyright Hugh Perkins (hughperkins at gmail), Josef Moudrik 2015
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "DeepCL.h"
#include "loss/SoftMaxLayer.h"
#ifdef _WIN32
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#endif // _WIN32

using namespace std;

/* [[[cog
    # These are used in the later cog sections in this file:
    options = [
        {'name': 'gpuIndex', 'type': 'int', 'description': 'gpu device index; default value is gpu if present, cpu otw.', 'default': -1, 'ispublicapi': True},

        {'name': 'weightsFile', 'type': 'string', 'description': 'file to read weights from', 'default': 'weights.dat', 'ispublicapi': True},
        # removing loadondemand for now, let's always load exactly one batch at a time for now
        # ('loadOnDemand', 'int', 'load data on demand [1|0]', 0, [0,1], True},
        {'name': 'batchSize', 'type': 'int', 'description': 'batch size', 'default': 128, 'ispublicapi': True},

        # lets go with pipe for now, and then somehow shoehorn files in later?
        {'name': 'inputFile',  'type': 'string', 'description': 'file to read inputs from, if empty, read stdin (default)', 'default': ''},
        {'name': 'outputFile', 'type': 'string', 'description': 'file to write outputs to, if empty, write to stdout', 'default': ''},
        {'name': 'outputLayer', 'type': 'int', 'description': 'layer to write output from, default -1 means: last layer', 'default': -1},
        {'name': 'writeLabels', 'type': 'int', 'description': 'write integer labels, instead of probabilities etc (default 0)', 'default': 0},
        {'name': 'outputFormat', 'type': 'string', 'description': 'output format [binary|text]', 'default': 'text'}
    ]
*///]]]
// [[[end]]]

class Config {
public:
    /* [[[cog
        cog.outl('// generated using cog:')
        for option in options:
            cog.outl( option['type'] + ' ' + option['name'] + ';')
    */// ]]]
    // generated using cog:
    int gpuIndex;
    string weightsFile;
    int batchSize;
    string inputFile;
    string outputFile;
    int outputLayer;
    int writeLabels;
    string outputFormat;
    // [[[end]]]

    Config() {
        /* [[[cog
            cog.outl('// generated using cog:')
            for option in options:
                defaultString = ''
                default = option['default']
                type = option['type']
                if type == 'string':
                    defaultString = '"' + default + '"'
                elif type == 'int':
                    defaultString = str(default)
                elif type == 'float':
                    defaultString = str(default)
                    if '.' not in defaultString:
                        defaultString += '.0'
                    defaultString += 'f'
                cog.outl( option['name'] + ' = ' + defaultString + ';')
        */// ]]]
        // generated using cog:
        gpuIndex = -1;
        weightsFile = "weights.dat";
        batchSize = 128;
        inputFile = "";
        outputFile = "";
        outputLayer = -1;
        writeLabels = 0;
        outputFormat = "text";
        // [[[end]]]
    }
};

void go(Config config) {
    bool verbose = true;
    if( config.outputFile == "" ) {
        verbose = false;
    }

    int N = -1;
    int numPlanes;
    int imageSize;
    int imageSizeCheck;
    if( config.inputFile == "" ) {
        int dims[3];
        cin.read( reinterpret_cast< char * >( dims ), 3 * 4l );
        numPlanes = dims[0];
        imageSize = dims[1];
        imageSizeCheck = dims[2];
        if( imageSize != imageSizeCheck ) {
            throw std::runtime_error( "imageSize doesnt match imageSizeCheck, image not square" );
        }
    } else {
        GenericLoader::getDimensions( config.inputFile, &N, &numPlanes, &imageSize );
        if( verbose ) cout << "N " << N << " planes " << numPlanes << " size " << imageSize << endl;
    }

    const long inputCubeSize = numPlanes * imageSize * imageSize ;

    //
    // ## Set up the Network
    //

    EasyCL *cl = 0;
    if( config.gpuIndex >= 0 ) {
        cl = EasyCL::createForIndexedGpu( config.gpuIndex, verbose );
    } else {
        cl = EasyCL::createForFirstGpuOtherwiseCpu( verbose );
    }

    NeuralNet *net;
    net = new NeuralNet(cl);

    // just use the default for net creation, weights are overriden from the weightsFile
    WeightsInitializer *weightsInitializer = new OriginalInitializer();

    if( config.weightsFile == "" ) {
        cout << "weightsFile not specified" << endl;
        return;
    }

    string netDef;
    if ( !WeightsPersister::loadConfigString( config.weightsFile, netDef ) ){
        cout << "Cannot load network definition from weightsFile." << endl;
        return;
    }
//    cout << "net def from weights file: " << netDef << endl;

    net->addLayer( InputLayerMaker::instance()->numPlanes(numPlanes)->imageSize(imageSize) );
    net->addLayer( NormalizationLayerMaker::instance()->translate( 0.0f )->scale( 1.0f ) ); // This will be read from weights file

    if( !NetdefToNet::createNetFromNetdef( net, netDef, weightsInitializer ) ) {
        return;
    }

    // ignored int and float, s.t. we can use loadWeights
    int ignI;
    float ignF;

    // weights file contains normalization layer parameters as 'weights' now.  We should probably rename weights to parameters
    // sooner or later ,but anyway, tehcnically, works for onw
    if( !WeightsPersister::loadWeights( config.weightsFile, string("netDef=")+netDef, net, &ignI, &ignI, &ignF, &ignI, &ignF ) ){
        cout << "Cannot load network weights from weightsFile." << endl;
        return;
    }

    if( verbose ) {
        net->print();
    }
    net->setBatchSize(config.batchSize);
    if( verbose ) cout << "batchSize: " << config.batchSize << endl;

    //
    // ## All is set up now
    //

    float *inputData = new float[ inputCubeSize * config.batchSize];

    int *labels = new int[config.batchSize];
    int n = 0;
    bool more = true;
    ostream *outFile = 0;
    if( verbose ) cout << "outputFile: '" << config.outputFile << "'"<< endl;
    if( config.outputFile == "" ) {
        outFile = &cout;
    } else {
        if( config.outputFormat == "text" ) {
            outFile = new ofstream( config.outputFile, ios::out );
        } else if( config.outputFormat == "binary" ) {
            outFile = new ofstream( config.outputFile, ios::out | std::ios::binary );
        } else {
            throw runtime_error( "outputFormat " + config.outputFormat + " not recognized" );
        }
    }
    if( config.outputLayer == -1 ) {
        config.outputLayer = net->getNumLayers() - 1;
    }
    if( verbose ) cout << "inputFile: '" << config.inputFile << "'"<< endl;
    if( config.inputFile == "" ) {
        #ifdef _WIN32
        // refs:
        // http://www.thecodingforums.com/threads/binary-output-to-stdout-in-windows.317367/
        // http://www.cplusplus.com/forum/windows/77812/
        _setmode( _fileno( stdout ), _O_BINARY );
        #endif
        cin.read( reinterpret_cast< char * >( inputData ), inputCubeSize * config.batchSize * 4l );
        more = !cin.eof();
    } else {
        // pass 0 for labels, and this will cause GenericLoader to simply not try to load any labels
        // now, after modifying GenericLoader to have this new behavior
        GenericLoader::load( config.inputFile, inputData, 0, n, config.batchSize );
    }
    while( more ) {
        // no point in forwarding through all, so forward through each, one by one
        if( config.outputLayer < 0 || config.outputLayer > net->getNumLayers() ) {
            throw runtime_error( "outputLayer should be the layer number of one of the layers in the network" );
        }
        dynamic_cast<InputLayer *>( net->getLayer(0) )->in( inputData );
        for( int layerId = 0; layerId <= config.outputLayer; layerId++ ) {
            StatefulTimer::setPrefix("layer" + toString(layerId) + " " );
            net->getLayer( layerId )->forward();
            StatefulTimer::setPrefix("" );
        }

        if( !config.writeLabels ) {
            if( config.outputFormat == "text" ) {
                float const*output = net->getLayer( config.outputLayer )->getOutput();
                const int numFields = net->getLayer( config.outputLayer )->getOutputCubeSize();
                for( int i = 0; i < config.batchSize; i++ ) {
                    for( int f = 0; f < numFields; f++ ) {
                        if( f > 0 ) {
                            *outFile << " ";
                        }
                        *outFile << output[ i * numFields + f ];
                    }
                    *outFile << "\n";
                }
            } else {
                outFile->write( reinterpret_cast<const char *>(net->getOutput()), net->getOutputSize() * 4 * config.batchSize);
            }
        } else {
            SoftMaxLayer *softMaxLayer = dynamic_cast< SoftMaxLayer *>(net->getLayer( config.outputLayer ) );
            if( softMaxLayer == 0 ) {
                cout << "must choose softmaxlayer, if want to output labels" << endl;
                return;
            }
            softMaxLayer->getLabels(labels);
            if( config.outputFormat == "text" ) {
                for( int i = 0; i < config.batchSize; i++ ) {
                    *outFile << labels[i] << "\n";
                }
            } else {
                outFile->write( reinterpret_cast< char * >( labels ), config.batchSize * 4l );
            }
            outFile->flush();
        }
        n += config.batchSize;
        if( config.inputFile == "" ) {
            cin.read( reinterpret_cast< char * >( inputData ), inputCubeSize * config.batchSize * 4l );
            more = !cin.eof();
        } else {
            if( n + config.batchSize < N ) {
                GenericLoader::load( config.inputFile, inputData, 0, n, config.batchSize );
            } else {
                more = false;
                if( n != N ) {
                    cout << "breaking prematurely, since file is not an exact multiple of batchsize, and we didnt handle this yet" << endl;
                }
            }
        }
    }
    if( config.outputFile != "" ) {
        delete outFile;
    }

    delete[] inputData;
    delete[] labels;
    delete weightsInitializer;
    delete net;
    delete cl;
}

void printUsage( char *argv[], Config config ) {
    cout << "Usage: " << argv[0] << " [key]=[value] [[key]=[value]] ..." << endl;
    cout << endl;
    cout << "Possible key=value pairs:" << endl;
    /* [[[cog
        cog.outl('// generated using cog:')
        cog.outl('cout << "public api, shouldnt change within major version:" << endl;')
        for option in options:
            name = option['name']
            description = option['description']
            if 'ispublicapi' in option and option['ispublicapi']:
                cog.outl( 'cout << "    ' + name.lower() + '=[' + description + '] (" << config.' + name + ' << ")" << endl;')
        cog.outl('cout << "" << endl; ')
        cog.outl('cout << "unstable, might change within major version:" << endl; ')
        for option in options:
            if 'ispublicapi' not in option or not option['ispublicapi']:
                name = option['name']
                description = option['description']
                cog.outl( 'cout << "    ' + name.lower() + '=[' + description + '] (" << config.' + name + ' << ")" << endl;')
    *///]]]
    // generated using cog:
    cout << "public api, shouldnt change within major version:" << endl;
    cout << "    gpuindex=[gpu device index; default value is gpu if present, cpu otw.] (" << config.gpuIndex << ")" << endl;
    cout << "    weightsfile=[file to read weights from] (" << config.weightsFile << ")" << endl;
    cout << "    batchsize=[batch size] (" << config.batchSize << ")" << endl;
    cout << "" << endl;
    cout << "unstable, might change within major version:" << endl;
    cout << "    inputfile=[file to read inputs from, if empty, read stdin (default)] (" << config.inputFile << ")" << endl;
    cout << "    outputfile=[file to write outputs to, if empty, write to stdout] (" << config.outputFile << ")" << endl;
    cout << "    outputlayer=[layer to write output from, default -1 means: last layer] (" << config.outputLayer << ")" << endl;
    cout << "    writelabels=[write integer labels, instead of probabilities etc (default 0)] (" << config.writeLabels << ")" << endl;
    cout << "    outputformat=[output format [binary|text]] (" << config.outputFormat << ")" << endl;
    // [[[end]]]
}

int main( int argc, char *argv[] ) {
    Config config;
    if( argc == 2 && ( string(argv[1]) == "--help" || string(argv[1]) == "--?" || string(argv[1]) == "-?" || string(argv[1]) == "-h" ) ) {
        printUsage( argv, config );
    }
    for( int i = 1; i < argc; i++ ) {
        vector<string> splitkeyval = split( argv[i], "=" );
        if( splitkeyval.size() != 2 ) {
          cout << "Usage: " << argv[0] << " [key]=[value] [[key]=[value]] ..." << endl;
          exit(1);
        } else {
            string key = splitkeyval[0];
            string value = splitkeyval[1];
//            cout << "key [" << key << "]" << endl;
            /* [[[cog
                cog.outl('// generated using cog:')
                cog.outl('if( false ) {')
                for option in options:
                    name = option['name']
                    type = option['type']
                    cog.outl( '} else if( key == "' + name.lower() + '" ) {')
                    converter = '';
                    if type == 'int':
                        converter = 'atoi';
                    elif type == 'float':
                        converter = 'atof';
                    cog.outl( '    config.' + name + ' = ' + converter + '(value);')
            */// ]]]
            // generated using cog:
            if( false ) {
            } else if( key == "gpuindex" ) {
                config.gpuIndex = atoi(value);
            } else if( key == "weightsfile" ) {
                config.weightsFile = (value);
            } else if( key == "batchsize" ) {
                config.batchSize = atoi(value);
            } else if( key == "inputfile" ) {
                config.inputFile = (value);
            } else if( key == "outputfile" ) {
                config.outputFile = (value);
            } else if( key == "outputlayer" ) {
                config.outputLayer = atoi(value);
            } else if( key == "writelabels" ) {
                config.writeLabels = atoi(value);
            } else if( key == "outputformat" ) {
                config.outputFormat = (value);
            // [[[end]]]
            } else {
                cout << endl;
                cout << "Error: key '" << key << "' not recognised" << endl;
                cout << endl;
                printUsage( argv, config );
                cout << endl;
                return -1;
            }
        }
    }
    if( config.outputFormat != "text" && config.outputFormat != "binary" ) {
        cout << endl;
        cout << "outputformat must be 'text' or 'binary'" << endl;
        cout << endl;
        return -1;
    }
    try {
        go( config );
    } catch( runtime_error e ) {
        cout << "Something went wrong: " << e.what() << endl;
        return -1;
    }
}

<commit_msg>predict: fix location of win32 binary setup<commit_after>// Copyright Hugh Perkins (hughperkins at gmail), Josef Moudrik 2015
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "DeepCL.h"
#include "loss/SoftMaxLayer.h"
#ifdef _WIN32
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#endif // _WIN32

using namespace std;

/* [[[cog
    # These are used in the later cog sections in this file:
    options = [
        {'name': 'gpuIndex', 'type': 'int', 'description': 'gpu device index; default value is gpu if present, cpu otw.', 'default': -1, 'ispublicapi': True},

        {'name': 'weightsFile', 'type': 'string', 'description': 'file to read weights from', 'default': 'weights.dat', 'ispublicapi': True},
        # removing loadondemand for now, let's always load exactly one batch at a time for now
        # ('loadOnDemand', 'int', 'load data on demand [1|0]', 0, [0,1], True},
        {'name': 'batchSize', 'type': 'int', 'description': 'batch size', 'default': 128, 'ispublicapi': True},

        # lets go with pipe for now, and then somehow shoehorn files in later?
        {'name': 'inputFile',  'type': 'string', 'description': 'file to read inputs from, if empty, read stdin (default)', 'default': ''},
        {'name': 'outputFile', 'type': 'string', 'description': 'file to write outputs to, if empty, write to stdout', 'default': ''},
        {'name': 'outputLayer', 'type': 'int', 'description': 'layer to write output from, default -1 means: last layer', 'default': -1},
        {'name': 'writeLabels', 'type': 'int', 'description': 'write integer labels, instead of probabilities etc (default 0)', 'default': 0},
        {'name': 'outputFormat', 'type': 'string', 'description': 'output format [binary|text]', 'default': 'text'}
    ]
*///]]]
// [[[end]]]

class Config {
public:
    /* [[[cog
        cog.outl('// generated using cog:')
        for option in options:
            cog.outl( option['type'] + ' ' + option['name'] + ';')
    */// ]]]
    // generated using cog:
    int gpuIndex;
    string weightsFile;
    int batchSize;
    string inputFile;
    string outputFile;
    int outputLayer;
    int writeLabels;
    string outputFormat;
    // [[[end]]]

    Config() {
        /* [[[cog
            cog.outl('// generated using cog:')
            for option in options:
                defaultString = ''
                default = option['default']
                type = option['type']
                if type == 'string':
                    defaultString = '"' + default + '"'
                elif type == 'int':
                    defaultString = str(default)
                elif type == 'float':
                    defaultString = str(default)
                    if '.' not in defaultString:
                        defaultString += '.0'
                    defaultString += 'f'
                cog.outl( option['name'] + ' = ' + defaultString + ';')
        */// ]]]
        // generated using cog:
        gpuIndex = -1;
        weightsFile = "weights.dat";
        batchSize = 128;
        inputFile = "";
        outputFile = "";
        outputLayer = -1;
        writeLabels = 0;
        outputFormat = "text";
        // [[[end]]]
    }
};

void go(Config config) {
    bool verbose = true;
    if( config.outputFile == "" ) {
        verbose = false;
    }

    int N = -1;
    int numPlanes;
    int imageSize;
    int imageSizeCheck;
    if( config.inputFile == "" ) {
        int dims[3];
        cin.read( reinterpret_cast< char * >( dims ), 3 * 4l );
        numPlanes = dims[0];
        imageSize = dims[1];
        imageSizeCheck = dims[2];
        if( imageSize != imageSizeCheck ) {
            throw std::runtime_error( "imageSize doesnt match imageSizeCheck, image not square" );
        }
    } else {
        GenericLoader::getDimensions( config.inputFile, &N, &numPlanes, &imageSize );
        if( verbose ) cout << "N " << N << " planes " << numPlanes << " size " << imageSize << endl;
    }

    const long inputCubeSize = numPlanes * imageSize * imageSize ;

    //
    // ## Set up the Network
    //

    EasyCL *cl = 0;
    if( config.gpuIndex >= 0 ) {
        cl = EasyCL::createForIndexedGpu( config.gpuIndex, verbose );
    } else {
        cl = EasyCL::createForFirstGpuOtherwiseCpu( verbose );
    }

    NeuralNet *net;
    net = new NeuralNet(cl);

    // just use the default for net creation, weights are overriden from the weightsFile
    WeightsInitializer *weightsInitializer = new OriginalInitializer();

    if( config.weightsFile == "" ) {
        cout << "weightsFile not specified" << endl;
        return;
    }

    string netDef;
    if ( !WeightsPersister::loadConfigString( config.weightsFile, netDef ) ){
        cout << "Cannot load network definition from weightsFile." << endl;
        return;
    }
//    cout << "net def from weights file: " << netDef << endl;

    net->addLayer( InputLayerMaker::instance()->numPlanes(numPlanes)->imageSize(imageSize) );
    net->addLayer( NormalizationLayerMaker::instance()->translate( 0.0f )->scale( 1.0f ) ); // This will be read from weights file

    if( !NetdefToNet::createNetFromNetdef( net, netDef, weightsInitializer ) ) {
        return;
    }

    // ignored int and float, s.t. we can use loadWeights
    int ignI;
    float ignF;

    // weights file contains normalization layer parameters as 'weights' now.  We should probably rename weights to parameters
    // sooner or later ,but anyway, tehcnically, works for onw
    if( !WeightsPersister::loadWeights( config.weightsFile, string("netDef=")+netDef, net, &ignI, &ignI, &ignF, &ignI, &ignF ) ){
        cout << "Cannot load network weights from weightsFile." << endl;
        return;
    }

    if( verbose ) {
        net->print();
    }
    net->setBatchSize(config.batchSize);
    if( verbose ) cout << "batchSize: " << config.batchSize << endl;

    //
    // ## All is set up now
    //

    float *inputData = new float[ inputCubeSize * config.batchSize];

    int *labels = new int[config.batchSize];
    int n = 0;
    bool more = true;
    ostream *outFile = 0;
    if( verbose ) cout << "outputFile: '" << config.outputFile << "'"<< endl;
    if( config.outputFile == "" ) {
        #ifdef _WIN32
        // refs:
        // http://www.thecodingforums.com/threads/binary-output-to-stdout-in-windows.317367/
        // http://www.cplusplus.com/forum/windows/77812/
        _setmode( _fileno( stdout ), _O_BINARY );
        #endif
        outFile = &cout;
    } else {
        if( config.outputFormat == "text" ) {
            outFile = new ofstream( config.outputFile, ios::out );
        } else if( config.outputFormat == "binary" ) {
            outFile = new ofstream( config.outputFile, ios::out | std::ios::binary );
        } else {
            throw runtime_error( "outputFormat " + config.outputFormat + " not recognized" );
        }
    }
    if( config.outputLayer == -1 ) {
        config.outputLayer = net->getNumLayers() - 1;
    }
    if( verbose ) cout << "inputFile: '" << config.inputFile << "'"<< endl;
    if( config.inputFile == "" ) {
        cin.read( reinterpret_cast< char * >( inputData ), inputCubeSize * config.batchSize * 4l );
        more = !cin.eof();
    } else {
        // pass 0 for labels, and this will cause GenericLoader to simply not try to load any labels
        // now, after modifying GenericLoader to have this new behavior
        GenericLoader::load( config.inputFile, inputData, 0, n, config.batchSize );
    }
    while( more ) {
        // no point in forwarding through all, so forward through each, one by one
        if( config.outputLayer < 0 || config.outputLayer > net->getNumLayers() ) {
            throw runtime_error( "outputLayer should be the layer number of one of the layers in the network" );
        }
        dynamic_cast<InputLayer *>( net->getLayer(0) )->in( inputData );
        for( int layerId = 0; layerId <= config.outputLayer; layerId++ ) {
            StatefulTimer::setPrefix("layer" + toString(layerId) + " " );
            net->getLayer( layerId )->forward();
            StatefulTimer::setPrefix("" );
        }

        if( !config.writeLabels ) {
            if( config.outputFormat == "text" ) {
                float const*output = net->getLayer( config.outputLayer )->getOutput();
                const int numFields = net->getLayer( config.outputLayer )->getOutputCubeSize();
                for( int i = 0; i < config.batchSize; i++ ) {
                    for( int f = 0; f < numFields; f++ ) {
                        if( f > 0 ) {
                            *outFile << " ";
                        }
                        *outFile << output[ i * numFields + f ];
                    }
                    *outFile << "\n";
                }
            } else {
                outFile->write( reinterpret_cast<const char *>(net->getOutput()), net->getOutputSize() * 4 * config.batchSize);
            }
        } else {
            SoftMaxLayer *softMaxLayer = dynamic_cast< SoftMaxLayer *>(net->getLayer( config.outputLayer ) );
            if( softMaxLayer == 0 ) {
                cout << "must choose softmaxlayer, if want to output labels" << endl;
                return;
            }
            softMaxLayer->getLabels(labels);
            if( config.outputFormat == "text" ) {
                for( int i = 0; i < config.batchSize; i++ ) {
                    *outFile << labels[i] << "\n";
                }
            } else {
                outFile->write( reinterpret_cast< char * >( labels ), config.batchSize * 4l );
            }
            outFile->flush();
        }
        n += config.batchSize;
        if( config.inputFile == "" ) {
            cin.read( reinterpret_cast< char * >( inputData ), inputCubeSize * config.batchSize * 4l );
            more = !cin.eof();
        } else {
            if( n + config.batchSize < N ) {
                GenericLoader::load( config.inputFile, inputData, 0, n, config.batchSize );
            } else {
                more = false;
                if( n != N ) {
                    cout << "breaking prematurely, since file is not an exact multiple of batchsize, and we didnt handle this yet" << endl;
                }
            }
        }
    }
    if( config.outputFile != "" ) {
        delete outFile;
    }

    delete[] inputData;
    delete[] labels;
    delete weightsInitializer;
    delete net;
    delete cl;
}

void printUsage( char *argv[], Config config ) {
    cout << "Usage: " << argv[0] << " [key]=[value] [[key]=[value]] ..." << endl;
    cout << endl;
    cout << "Possible key=value pairs:" << endl;
    /* [[[cog
        cog.outl('// generated using cog:')
        cog.outl('cout << "public api, shouldnt change within major version:" << endl;')
        for option in options:
            name = option['name']
            description = option['description']
            if 'ispublicapi' in option and option['ispublicapi']:
                cog.outl( 'cout << "    ' + name.lower() + '=[' + description + '] (" << config.' + name + ' << ")" << endl;')
        cog.outl('cout << "" << endl; ')
        cog.outl('cout << "unstable, might change within major version:" << endl; ')
        for option in options:
            if 'ispublicapi' not in option or not option['ispublicapi']:
                name = option['name']
                description = option['description']
                cog.outl( 'cout << "    ' + name.lower() + '=[' + description + '] (" << config.' + name + ' << ")" << endl;')
    *///]]]
    // generated using cog:
    cout << "public api, shouldnt change within major version:" << endl;
    cout << "    gpuindex=[gpu device index; default value is gpu if present, cpu otw.] (" << config.gpuIndex << ")" << endl;
    cout << "    weightsfile=[file to read weights from] (" << config.weightsFile << ")" << endl;
    cout << "    batchsize=[batch size] (" << config.batchSize << ")" << endl;
    cout << "" << endl;
    cout << "unstable, might change within major version:" << endl;
    cout << "    inputfile=[file to read inputs from, if empty, read stdin (default)] (" << config.inputFile << ")" << endl;
    cout << "    outputfile=[file to write outputs to, if empty, write to stdout] (" << config.outputFile << ")" << endl;
    cout << "    outputlayer=[layer to write output from, default -1 means: last layer] (" << config.outputLayer << ")" << endl;
    cout << "    writelabels=[write integer labels, instead of probabilities etc (default 0)] (" << config.writeLabels << ")" << endl;
    cout << "    outputformat=[output format [binary|text]] (" << config.outputFormat << ")" << endl;
    // [[[end]]]
}

int main( int argc, char *argv[] ) {
    Config config;
    if( argc == 2 && ( string(argv[1]) == "--help" || string(argv[1]) == "--?" || string(argv[1]) == "-?" || string(argv[1]) == "-h" ) ) {
        printUsage( argv, config );
    }
    for( int i = 1; i < argc; i++ ) {
        vector<string> splitkeyval = split( argv[i], "=" );
        if( splitkeyval.size() != 2 ) {
          cout << "Usage: " << argv[0] << " [key]=[value] [[key]=[value]] ..." << endl;
          exit(1);
        } else {
            string key = splitkeyval[0];
            string value = splitkeyval[1];
//            cout << "key [" << key << "]" << endl;
            /* [[[cog
                cog.outl('// generated using cog:')
                cog.outl('if( false ) {')
                for option in options:
                    name = option['name']
                    type = option['type']
                    cog.outl( '} else if( key == "' + name.lower() + '" ) {')
                    converter = '';
                    if type == 'int':
                        converter = 'atoi';
                    elif type == 'float':
                        converter = 'atof';
                    cog.outl( '    config.' + name + ' = ' + converter + '(value);')
            */// ]]]
            // generated using cog:
            if( false ) {
            } else if( key == "gpuindex" ) {
                config.gpuIndex = atoi(value);
            } else if( key == "weightsfile" ) {
                config.weightsFile = (value);
            } else if( key == "batchsize" ) {
                config.batchSize = atoi(value);
            } else if( key == "inputfile" ) {
                config.inputFile = (value);
            } else if( key == "outputfile" ) {
                config.outputFile = (value);
            } else if( key == "outputlayer" ) {
                config.outputLayer = atoi(value);
            } else if( key == "writelabels" ) {
                config.writeLabels = atoi(value);
            } else if( key == "outputformat" ) {
                config.outputFormat = (value);
            // [[[end]]]
            } else {
                cout << endl;
                cout << "Error: key '" << key << "' not recognised" << endl;
                cout << endl;
                printUsage( argv, config );
                cout << endl;
                return -1;
            }
        }
    }
    if( config.outputFormat != "text" && config.outputFormat != "binary" ) {
        cout << endl;
        cout << "outputformat must be 'text' or 'binary'" << endl;
        cout << endl;
        return -1;
    }
    try {
        go( config );
    } catch( runtime_error e ) {
        cout << "Something went wrong: " << e.what() << endl;
        return -1;
    }
}

<|endoftext|>