<commit_before>/*
    Copyright (C) 2014  P.L. Lucas <selairi@gmail.com>
    Copyright (C) 2013  <copyright holder> <email>

    This program 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 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "monitorsettingsdialog.h"

#include "monitorwidget.h"
#include "timeoutdialog.h"
#include "monitorpicture.h"
#include "settingsdialog.h"

#include <KScreen/Output>
#include <QJsonObject>
#include <QJsonArray>
#include <QSettings>
#include <QJsonDocument>
#include <KScreen/EDID>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>

MonitorSettingsDialog::MonitorSettingsDialog() :
    QDialog(nullptr, 0)
{
    ui.setupUi(this);

    KScreen::GetConfigOperation *operation = new KScreen::GetConfigOperation();
    connect(operation, &KScreen::GetConfigOperation::finished, [this, operation] (KScreen::ConfigOperation *op) {
        KScreen::GetConfigOperation *configOp = qobject_cast<KScreen::GetConfigOperation *>(op);
        if (configOp)
        {
            mOldConfig = configOp->config()->clone();
            loadConfiguration(configOp->config());
            operation->deleteLater();
        }
    });

    connect(ui.buttonBox, &QDialogButtonBox::clicked, [&] (QAbstractButton *button) {
        if (ui.buttonBox->standardButton(button) == QDialogButtonBox::Apply)
            applyConfiguration(false);
        if (ui.buttonBox->standardButton(button) == QDialogButtonBox::Save)
        {
            applyConfiguration(true);
        }

    });

    ui.settingsButton->hide(); // Hide settings button until daemon works OK.
    connect(ui.settingsButton, SIGNAL(clicked()), this, SLOT(showSettingsDialog()));
}

MonitorSettingsDialog::~MonitorSettingsDialog()
{
}

void MonitorSettingsDialog::loadConfiguration(KScreen::ConfigPtr config)
{
    if (mConfig == config)
        return;

    mConfig = config;

    MonitorPictureDialog *monitorPicture = nullptr;
    KScreen::OutputList outputs = mConfig->outputs();

    int nMonitors = 0;
    for (const KScreen::OutputPtr &output : outputs)
    {
        if (output->isConnected())
            nMonitors++;

        if (nMonitors > 1)
        {
            monitorPicture = new MonitorPictureDialog(config, this);
            ui.monitorList->addItem(tr("Set position"));
            ui.stackedWidget->addWidget(monitorPicture);
            break;
        }
    }

    QList<MonitorWidget*> monitors;

    for (const KScreen::OutputPtr &output : outputs)
    {
        if (output->isConnected())
        {
            MonitorWidget *monitor = new MonitorWidget(output, mConfig, this);
            ui.monitorList->addItem(output->name());
            ui.stackedWidget->addWidget(monitor);
            monitors.append(monitor);
        }
    }

    if (monitorPicture)
        monitorPicture->setScene(monitors);

    ui.monitorList->setCurrentRow(0);
    adjustSize();
}

void MonitorSettingsDialog::applyConfiguration(bool saveConfigOk)
{
    if (mConfig && KScreen::Config::canBeApplied(mConfig))
    {
        KScreen::SetConfigOperation(mConfig).exec();

        TimeoutDialog mTimeoutDialog;
        if (mTimeoutDialog.exec() == QDialog::Rejected)
            KScreen::SetConfigOperation(mOldConfig).exec();
        else
        {
            mOldConfig = mConfig->clone();
            if (saveConfigOk)
                saveConfiguration(mConfig);
        }
    }
}

void MonitorSettingsDialog::accept()
{
    //applyConfiguration(true);
    QDialog::accept();
}

void MonitorSettingsDialog::reject()
{
    QDialog::reject();
}

void MonitorSettingsDialog::saveConfiguration(KScreen::ConfigPtr config)
{
    QJsonObject json;
    QJsonArray jsonArray;
    KScreen::OutputList outputs = config->outputs();
    for (const KScreen::OutputPtr &output : outputs)
    {
        QJsonObject monitorSettings;
        monitorSettings["name"] = output->name();
        KScreen::Edid* edid = output->edid();
        if (edid && edid->isValid())
            monitorSettings["hash"] = edid->hash();
        monitorSettings["connected"] = output->isConnected();
        if ( output->isConnected() )
        {
            monitorSettings["enabled"] = output->isEnabled();
            monitorSettings["primary"] = output->isPrimary();
            monitorSettings["xPos"] = output->pos().x();
            monitorSettings["yPos"] = output->pos().y();
            monitorSettings["currentMode"] = output->currentMode()->id();
            monitorSettings["rotation"] = output->rotation();
        }
        jsonArray.append(monitorSettings);
    }
    json["outputs"] = jsonArray;

    QSettings settings("LXQt", "lxqt-config-monitor");
    settings.setValue("currentConfig", QVariant(QJsonDocument(json).toJson()));

    QString desktop = QString("[Desktop Entry]\n"
                              "Type=Application\n"
                              "Name=LXQt-config-monitor autostart\n"
                              "Comment=Autostart monitor settings for LXQt-config-monitor\n"
                              "Exec=%1\n"
                              "OnlyShowIn=LXQt\n").arg("lxqt-config-monitor -l");

    // Check autostart path: $XDG_CONFIG_HOME or ~/.config/autostart
    QString autostartPath;
    bool ok = true;
    if(qEnvironmentVariableIsSet("XDG_CONFIG_HOME"))
        autostartPath = QString(qgetenv("XDG_CONFIG_HOME"));
    else
    {
         autostartPath = QDir::homePath() + "/.config/autostart/";
        // Check if ~/.config/autostart/ exists
        QFileInfo fileInfo(autostartPath);
        if( ! fileInfo.exists() )
            ok = QDir::root().mkpath(autostartPath);
    }
    QFile file(autostartPath + "/lxqt-config-monitor-autostart.desktop");
    if(ok)
            ok = file.open(QIODevice::WriteOnly | QIODevice::Text);
    if(!ok) {
      QMessageBox::critical(this, tr("Error"), tr("Config can not be saved"));
      return;
    }
    QTextStream out(&file);
    out << desktop;
    out.flush();
    file.close();

}

void MonitorSettingsDialog::showSettingsDialog()
{
    QByteArray configName = qgetenv("LXQT_SESSION_CONFIG");

    if (configName.isEmpty())
        configName = "MonitorSettings";

    LXQt::Settings settings(configName);

    SettingsDialog settingsDialog(tr("Advanced settings"), &settings);
    settingsDialog.exec();
}
<commit_msg>Mkdir $XDG_CONFIG_HOME/autostart or ~/.config/autostart, if not exists.<commit_after>/*
    Copyright (C) 2014  P.L. Lucas <selairi@gmail.com>
    Copyright (C) 2013  <copyright holder> <email>

    This program 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 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "monitorsettingsdialog.h"

#include "monitorwidget.h"
#include "timeoutdialog.h"
#include "monitorpicture.h"
#include "settingsdialog.h"

#include <KScreen/Output>
#include <QJsonObject>
#include <QJsonArray>
#include <QSettings>
#include <QJsonDocument>
#include <KScreen/EDID>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>

MonitorSettingsDialog::MonitorSettingsDialog() :
    QDialog(nullptr, 0)
{
    ui.setupUi(this);

    KScreen::GetConfigOperation *operation = new KScreen::GetConfigOperation();
    connect(operation, &KScreen::GetConfigOperation::finished, [this, operation] (KScreen::ConfigOperation *op) {
        KScreen::GetConfigOperation *configOp = qobject_cast<KScreen::GetConfigOperation *>(op);
        if (configOp)
        {
            mOldConfig = configOp->config()->clone();
            loadConfiguration(configOp->config());
            operation->deleteLater();
        }
    });

    connect(ui.buttonBox, &QDialogButtonBox::clicked, [&] (QAbstractButton *button) {
        if (ui.buttonBox->standardButton(button) == QDialogButtonBox::Apply)
            applyConfiguration(false);
        if (ui.buttonBox->standardButton(button) == QDialogButtonBox::Save)
        {
            applyConfiguration(true);
        }

    });

    ui.settingsButton->hide(); // Hide settings button until daemon works OK.
    connect(ui.settingsButton, SIGNAL(clicked()), this, SLOT(showSettingsDialog()));
}

MonitorSettingsDialog::~MonitorSettingsDialog()
{
}

void MonitorSettingsDialog::loadConfiguration(KScreen::ConfigPtr config)
{
    if (mConfig == config)
        return;

    mConfig = config;

    MonitorPictureDialog *monitorPicture = nullptr;
    KScreen::OutputList outputs = mConfig->outputs();

    int nMonitors = 0;
    for (const KScreen::OutputPtr &output : outputs)
    {
        if (output->isConnected())
            nMonitors++;

        if (nMonitors > 1)
        {
            monitorPicture = new MonitorPictureDialog(config, this);
            ui.monitorList->addItem(tr("Set position"));
            ui.stackedWidget->addWidget(monitorPicture);
            break;
        }
    }

    QList<MonitorWidget*> monitors;

    for (const KScreen::OutputPtr &output : outputs)
    {
        if (output->isConnected())
        {
            MonitorWidget *monitor = new MonitorWidget(output, mConfig, this);
            ui.monitorList->addItem(output->name());
            ui.stackedWidget->addWidget(monitor);
            monitors.append(monitor);
        }
    }

    if (monitorPicture)
        monitorPicture->setScene(monitors);

    ui.monitorList->setCurrentRow(0);
    adjustSize();
}

void MonitorSettingsDialog::applyConfiguration(bool saveConfigOk)
{
    if (mConfig && KScreen::Config::canBeApplied(mConfig))
    {
        KScreen::SetConfigOperation(mConfig).exec();

        TimeoutDialog mTimeoutDialog;
        if (mTimeoutDialog.exec() == QDialog::Rejected)
            KScreen::SetConfigOperation(mOldConfig).exec();
        else
        {
            mOldConfig = mConfig->clone();
            if (saveConfigOk)
                saveConfiguration(mConfig);
        }
    }
}

void MonitorSettingsDialog::accept()
{
    //applyConfiguration(true);
    QDialog::accept();
}

void MonitorSettingsDialog::reject()
{
    QDialog::reject();
}

void MonitorSettingsDialog::saveConfiguration(KScreen::ConfigPtr config)
{
    QJsonObject json;
    QJsonArray jsonArray;
    KScreen::OutputList outputs = config->outputs();
    for (const KScreen::OutputPtr &output : outputs)
    {
        QJsonObject monitorSettings;
        monitorSettings["name"] = output->name();
        KScreen::Edid* edid = output->edid();
        if (edid && edid->isValid())
            monitorSettings["hash"] = edid->hash();
        monitorSettings["connected"] = output->isConnected();
        if ( output->isConnected() )
        {
            monitorSettings["enabled"] = output->isEnabled();
            monitorSettings["primary"] = output->isPrimary();
            monitorSettings["xPos"] = output->pos().x();
            monitorSettings["yPos"] = output->pos().y();
            monitorSettings["currentMode"] = output->currentMode()->id();
            monitorSettings["rotation"] = output->rotation();
        }
        jsonArray.append(monitorSettings);
    }
    json["outputs"] = jsonArray;

    QSettings settings("LXQt", "lxqt-config-monitor");
    settings.setValue("currentConfig", QVariant(QJsonDocument(json).toJson()));

    QString desktop = QString("[Desktop Entry]\n"
                              "Type=Application\n"
                              "Name=LXQt-config-monitor autostart\n"
                              "Comment=Autostart monitor settings for LXQt-config-monitor\n"
                              "Exec=%1\n"
                              "OnlyShowIn=LXQt\n").arg("lxqt-config-monitor -l");

    // Check autostart path: $XDG_CONFIG_HOME or ~/.config/autostart
    QString autostartPath;
    bool ok = true;
    if(qEnvironmentVariableIsSet("XDG_CONFIG_HOME"))
        autostartPath = QString(qgetenv("XDG_CONFIG_HOME")) + "/autostart/";
    else
         autostartPath = QDir::homePath() + "/.config/autostart/";

    // Check if ~/.config/autostart/ exists
    QFileInfo fileInfo(autostartPath);
    if( ! fileInfo.exists() )
        ok = QDir::root().mkpath(autostartPath);

    QFile file(autostartPath + "/lxqt-config-monitor-autostart.desktop");
    if(ok)
            ok = file.open(QIODevice::WriteOnly | QIODevice::Text);
    if(!ok) {
      QMessageBox::critical(this, tr("Error"), tr("Config can not be saved"));
      return;
    }
    QTextStream out(&file);
    out << desktop;
    out.flush();
    file.close();

}

void MonitorSettingsDialog::showSettingsDialog()
{
    QByteArray configName = qgetenv("LXQT_SESSION_CONFIG");

    if (configName.isEmpty())
        configName = "MonitorSettings";

    LXQt::Settings settings(configName);

    SettingsDialog settingsDialog(tr("Advanced settings"), &settings);
    settingsDialog.exec();
}
<|endoftext|>


<commit_before>// This file is part of the HörTech Open Master Hearing Aid (openMHA)
// Copyright © 2017 2018 HörTech gGmbH
//
// openMHA 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, version 3 of the License.
//
// openMHA 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, version 3 for more details.
//
// You should have received a copy of the GNU Affero General Public License,
// version 3 along with openMHA.  If not, see <http://www.gnu.org/licenses/>.

#include "mha_tablelookup.hh"
#include <gtest/gtest.h>
#include <math.h>
// Test linear interpolation between 3 mesh points
class MHATableLookup_xy_linear_interpolation : public ::testing::Test {
public:
  MHATableLookup::xy_table_t t;
  void SetUp() {
    t.add_entry(  0,   0);
    t.add_entry(100, 100);
    t.add_entry(300,-100);
  }
};

TEST_F(MHATableLookup_xy_linear_interpolation, values_at_mesh_points) {
  EXPECT_EQ(   0, t.interp(  0));
  EXPECT_EQ( 100, t.interp(100));
  EXPECT_EQ(-100, t.interp(300));
}
TEST_F(MHATableLookup_xy_linear_interpolation, interpolate_between_mesh_points)
{
  EXPECT_EQ( 1.0f,  t.interp(  1));
  EXPECT_EQ(99.0f,  t.interp( 99));
  EXPECT_EQ(99.0f,  t.interp(101));
  EXPECT_EQ( 0.0f,  t.interp(200));
}
TEST_F(MHATableLookup_xy_linear_interpolation, table_extrapolates) {
  EXPECT_EQ( -10.0f,  t.interp(-10));
  EXPECT_EQ(-200.0f,  t.interp(400));
}

// Test interpolation on logarithmic x axis between 3 mesh points
class MHATableLookup_xy_log_interpolation : public ::testing::Test {
public:
  MHATableLookup::xy_table_t t;
  void SetUp() {
    t.set_xfun(logf); // set log domain
    float frequencies[] = {125,500,1000};
    float gains[] = {20,0,30};
    t.add_entry(frequencies, gains, 3);
  }
};

TEST_F(MHATableLookup_xy_log_interpolation, values_at_mesh_points) {
  EXPECT_FLOAT_EQ(20, t.interp( 125));
  EXPECT_FLOAT_EQ( 0, t.interp( 500));
  EXPECT_FLOAT_EQ(30, t.interp(1000));
}
TEST_F(MHATableLookup_xy_log_interpolation, interpolate_between_mesh_points) {
  EXPECT_FLOAT_EQ(10.0f,  t.interp(250));
  EXPECT_NEAR(15.0f, t.interp(sqrtf(500*1000)),     15e-6f);
  EXPECT_NEAR(1,     t.interp(500 * pow(2,1.0/30)), 15e-6f);
}
TEST_F(MHATableLookup_xy_log_interpolation, table_extrapolates) {
  EXPECT_FLOAT_EQ(  30.0f,  t.interp(125.0f/2));
  EXPECT_FLOAT_EQ(  60.0f,  t.interp(2000));
}

// The following tests are for class linear_table_t, which is limited to
// equidistant x mesh points

// Test linear_table interpolation between 3 mesh points
class MHATableLookup_linear_table : public ::testing::Test {
public:
  MHATableLookup::linear_table_t t;
  struct point {float x, y;}
    points[3] = {{100,   0},
                 {107, 100},
                 {114,  50},
                 // next point would be at 121
    };
  void SetUp() {
    t.set_xmin(points[0].x);  // xmin is the x of the first entry
    // now add the y of all points in correct order from low x to high x
    t.add_entry(points[0].y); //   0.0f {x = 100, y = 0}
    t.add_entry(points[1].y); // 100.0f {x = 107, y = 100}
    t.add_entry(points[2].y); //  50.0f {x = 114, y = 50}

    // set xmax to the x of the entry that would follow next, but does not
    t.set_xmax(points[2].x + 7);

    // let the object compute the distance between the x values
    t.prepare();
  }
};
TEST_F(MHATableLookup_linear_table, values_at_mesh_points) {
  for (point p : points) {
    EXPECT_FLOAT_EQ(p.y, t.lookup(p.x));
    EXPECT_FLOAT_EQ(p.y, t.interp(p.x));
  }
}

TEST_F(MHATableLookup_linear_table, interpolate_between_mesh_points) {
  EXPECT_FLOAT_EQ(50.0f, t.interp(103.5f));
  EXPECT_FLOAT_EQ( 0.0f, t.lookup(103.5f));

  EXPECT_FLOAT_EQ(75.0f, t.interp(110.5f));
  EXPECT_FLOAT_EQ(100.f, t.lookup(110.5f));

  // lookup will return the y for the x meshpoint with lesser x than looked up
  // even if the meshpoint with higher x is nearer
  EXPECT_FLOAT_EQ( 0.0f, t.lookup(106.0f));
  EXPECT_FLOAT_EQ(100.f, t.lookup(113.0f));
}

TEST_F(MHATableLookup_linear_table, table_extrapolates) {

  // the interp method extrapolates
  EXPECT_FLOAT_EQ(-100.0f,  t.interp(93));
  EXPECT_NEAR(       0.0f,  t.interp(121), 2e-5f);
  EXPECT_FLOAT_EQ( -50.0f,  t.interp(128));

  // but the lookup method does not extrapolate
  EXPECT_FLOAT_EQ(   0.0f,  t.lookup(93));
  EXPECT_FLOAT_EQ(  50.0f,  t.lookup(121));
  EXPECT_FLOAT_EQ(  50.0f,  t.lookup(128));
}

// Local Variables:
// compile-command: "make -C .. unit-tests"
// coding: utf-8-unix
// c-basic-offset: 2
// indent-tabs-mode: nil
// End:
<commit_msg>Tranlate cppunit tests to googletest<commit_after>// This file is part of the HörTech Open Master Hearing Aid (openMHA)
// Copyright © 2017 2018 HörTech gGmbH
//
// openMHA 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, version 3 of the License.
//
// openMHA 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, version 3 for more details.
//
// You should have received a copy of the GNU Affero General Public License,
// version 3 along with openMHA.  If not, see <http://www.gnu.org/licenses/>.

#include "mha_tablelookup.hh"
#include <gtest/gtest.h>
#include <math.h>
// Test linear interpolation between 3 mesh points
class MHATableLookup_xy_linear_interpolation : public ::testing::Test {
public:
  MHATableLookup::xy_table_t t;
  void SetUp() {
    t.add_entry(  0,   0);
    t.add_entry(100, 100);
    t.add_entry(300,-100);
  }
};

TEST_F(MHATableLookup_xy_linear_interpolation, values_at_mesh_points) {
  EXPECT_EQ(   0, t.interp(  0));
  EXPECT_EQ( 100, t.interp(100));
  EXPECT_EQ(-100, t.interp(300));
}
TEST_F(MHATableLookup_xy_linear_interpolation, interpolate_between_mesh_points)
{
  EXPECT_EQ( 1.0f,  t.interp(  1));
  EXPECT_EQ(99.0f,  t.interp( 99));
  EXPECT_EQ(99.0f,  t.interp(101));
  EXPECT_EQ( 0.0f,  t.interp(200));
}
TEST_F(MHATableLookup_xy_linear_interpolation, table_extrapolates) {
  EXPECT_EQ( -10.0f,  t.interp(-10));
  EXPECT_EQ(-200.0f,  t.interp(400));
}

// Test interpolation on logarithmic x axis between 3 mesh points
class MHATableLookup_xy_log_interpolation : public ::testing::Test {
public:
  MHATableLookup::xy_table_t t;
  void SetUp() {
    t.set_xfun(logf); // set log domain
    float frequencies[] = {125,500,1000};
    float gains[] = {20,0,30};
    t.add_entry(frequencies, gains, 3);
  }
};

TEST_F(MHATableLookup_xy_log_interpolation, values_at_mesh_points) {
  EXPECT_FLOAT_EQ(20, t.interp( 125));
  EXPECT_FLOAT_EQ( 0, t.interp( 500));
  EXPECT_FLOAT_EQ(30, t.interp(1000));
}
TEST_F(MHATableLookup_xy_log_interpolation, interpolate_between_mesh_points) {
  EXPECT_FLOAT_EQ(10.0f,  t.interp(250));
  EXPECT_NEAR(15.0f, t.interp(sqrtf(500*1000)),     15e-6f);
  EXPECT_NEAR(1,     t.interp(500 * pow(2,1.0/30)), 15e-6f);
}
TEST_F(MHATableLookup_xy_log_interpolation, table_extrapolates) {
  EXPECT_FLOAT_EQ(  30.0f,  t.interp(125.0f/2));
  EXPECT_FLOAT_EQ(  60.0f,  t.interp(2000));
}

// The following tests are for class linear_table_t, which is limited to
// equidistant x mesh points

// Test linear_table interpolation between 3 mesh points
class MHATableLookup_linear_table : public ::testing::Test {
public:
  MHATableLookup::linear_table_t t;
  struct point {float x, y;}
    points[3] = {{100,   0},
                 {107, 100},
                 {114,  50},
                 // next point would be at 121
    };
  void SetUp() {
    t.set_xmin(points[0].x);  // xmin is the x of the first entry
    // now add the y of all points in correct order from low x to high x
    t.add_entry(points[0].y); //   0.0f {x = 100, y = 0}
    t.add_entry(points[1].y); // 100.0f {x = 107, y = 100}
    t.add_entry(points[2].y); //  50.0f {x = 114, y = 50}

    // set xmax to the x of the entry that would follow next, but does not
    t.set_xmax(points[2].x + 7);

    // let the object compute the distance between the x values
    t.prepare();
  }
};
TEST_F(MHATableLookup_linear_table, values_at_mesh_points) {
  for (point p : points) {
    EXPECT_FLOAT_EQ(p.y, t.lookup(p.x));
    EXPECT_FLOAT_EQ(p.y, t.interp(p.x));
  }
}

TEST_F(MHATableLookup_linear_table, interpolate_between_mesh_points) {
  EXPECT_FLOAT_EQ(50.0f, t.interp(103.5f));
  EXPECT_FLOAT_EQ( 0.0f, t.lookup(103.5f));

  EXPECT_FLOAT_EQ(75.0f, t.interp(110.5f));
  EXPECT_FLOAT_EQ(100.f, t.lookup(110.5f));

  // lookup will return the y for the x meshpoint with lesser x than looked up
  // even if the meshpoint with higher x is nearer
  EXPECT_FLOAT_EQ( 0.0f, t.lookup(106.0f));
  EXPECT_FLOAT_EQ(100.f, t.lookup(113.0f));
}

TEST_F(MHATableLookup_linear_table, table_extrapolates) {

  // the interp method extrapolates
  EXPECT_FLOAT_EQ(-100.0f,  t.interp(93));
  EXPECT_NEAR(       0.0f,  t.interp(121), 2e-5f);
  EXPECT_FLOAT_EQ( -50.0f,  t.interp(128));

  // but the lookup method does not extrapolate
  EXPECT_FLOAT_EQ(   0.0f,  t.lookup(93));
  EXPECT_FLOAT_EQ(  50.0f,  t.lookup(121));
  EXPECT_FLOAT_EQ(  50.0f,  t.lookup(128));
}

// =================================================

// Older tests translated from cppunit to googletest
using MHATableLookup::xy_table_t;

TEST(xy_table_t, lookup_InRange)
{
    xy_table_t xy;
    xy.add_entry(1.0f,2.0f);
    xy.add_entry(2.0f,4.0f);
    xy.add_entry(3.0f,6.0f);
    EXPECT_EQ(2.0f,xy.lookup(1.0f));
    EXPECT_EQ(4.0f,xy.lookup(2.0f));
    EXPECT_EQ(4.0f,xy.lookup(2.4f));
    EXPECT_EQ(4.0f,xy.lookup(1.6f));
    EXPECT_EQ(6.0f,xy.lookup(2.6f));
    EXPECT_EQ(6.0f,xy.lookup(3.0f));
}

TEST(xy_table_t, test_interp_InRange)
{
    xy_table_t xy;
    xy.add_entry(1.0f,2.0f);
    xy.add_entry(2.0f,4.0f);
    xy.add_entry(3.0f,6.0f);
    EXPECT_EQ(2.0f,xy.interp(1.0f));
    EXPECT_EQ(4.0f,xy.interp(2.0f));
    EXPECT_EQ(4.8f,xy.interp(2.4f));
    EXPECT_EQ(3.2f,xy.interp(1.6f));
    EXPECT_EQ(5.2f,xy.interp(2.6f));
    EXPECT_EQ(6.0f,xy.interp(3.0f));
}

TEST(xy_table_t, test_lookup_OutOfRange)
{
    xy_table_t xy;
    xy.add_entry(1.0f,2.0f);
    xy.add_entry(2.0f,4.0f);
    xy.add_entry(3.0f,6.0f);
    EXPECT_EQ(2.0f,xy.lookup(-2.2f));
    EXPECT_EQ(2.0f,xy.lookup(-1.0f));
    EXPECT_EQ(6.0f,xy.lookup(3.2f));
    EXPECT_EQ(6.0f,xy.lookup(13.2f));
}

TEST(xy_table_t, test_interp_OutOfRange)
{
    xy_table_t xy;
    xy.add_entry(1.0f,2.0f);
    xy.add_entry(2.0f,4.0f);
    xy.add_entry(3.0f,6.0f);
    EXPECT_EQ(-4.4f,xy.interp(-2.2f));
    EXPECT_EQ(-2.0f,xy.interp(-1.0f));
    EXPECT_EQ(6.4f,xy.interp(3.2f));
    EXPECT_EQ(26.4f,xy.interp(13.2f));
}

TEST(xy_table_t, test_interp_SingleEntry)
{
    xy_table_t xy;
    xy.add_entry(1.0f,2.0f);
    EXPECT_EQ(2.0f,xy.interp(-2.2f));
    EXPECT_EQ(2.0f,xy.interp(1.0f));
    EXPECT_EQ(2.0f,xy.interp(2.3f));
}

TEST(xy_table_t, test_interp_NonMonotonicInsertion)
{
    xy_table_t xy;
    xy.add_entry(1.0f,2.0f);
    xy.add_entry(2.0f,4.0f);
    xy.add_entry(3.0f,6.0f);
    EXPECT_EQ(4.4f,xy.interp(2.2f));
    xy.add_entry(2.4f,-1.0f);
    EXPECT_EQ(1.5f,xy.interp(2.2f));
    EXPECT_EQ(-1.0f,xy.interp(2.4f));
}

TEST(xy_table_t, test_interp_XFun)
{
    xy_table_t xy;
    xy.set_xfun(logf);
    xy.add_entry(1.0f,2.0f);
    xy.add_entry(2.0f,4.0f);
    xy.add_entry(8.0f,6.0f);
    EXPECT_EQ(2.0f,xy.interp(1.0f));
    EXPECT_EQ(4.0f,xy.interp(2.0f));
    EXPECT_EQ(6.0f,xy.interp(8.0f));
    EXPECT_EQ(5.0f,xy.interp(4.0f));
    EXPECT_EQ(3.0f,xy.interp(1.414213562373095145f));
}

// Local Variables:
// compile-command: "make -C .. unit-tests"
// coding: utf-8-unix
// c-basic-offset: 2
// indent-tabs-mode: nil
// End:
<|endoftext|>


<commit_before>// Reverb model implementation
//
//
// Google Summer of Code 2007
//
// Authors: Biodun Osunkunle <biodun@videolan.org>
//
// Mentor : Jean-Baptiste Kempf <jb@videolan.org>
//
// Original written by Jezar at Dreampoint, June 2000

// This code is public domain

#include "revmodel.hpp"
#include <stdlib.h>

revmodel::revmodel()
{
    // Tie the components to their buffers
    combL[0].setbuffer(bufcombL1,combtuningL1);
    combR[0].setbuffer(bufcombR1,combtuningR1);
    combL[1].setbuffer(bufcombL2,combtuningL2);
    combR[1].setbuffer(bufcombR2,combtuningR2);
    combL[2].setbuffer(bufcombL3,combtuningL3);
    combR[2].setbuffer(bufcombR3,combtuningR3);
    combL[3].setbuffer(bufcombL4,combtuningL4);
    combR[3].setbuffer(bufcombR4,combtuningR4);
    combL[4].setbuffer(bufcombL5,combtuningL5);
    combR[4].setbuffer(bufcombR5,combtuningR5);
    combL[5].setbuffer(bufcombL6,combtuningL6);
    combR[5].setbuffer(bufcombR6,combtuningR6);
    combL[6].setbuffer(bufcombL7,combtuningL7);
    combR[6].setbuffer(bufcombR7,combtuningR7);
    combL[7].setbuffer(bufcombL8,combtuningL8);
    combR[7].setbuffer(bufcombR8,combtuningR8);
    allpassL[0].setbuffer(bufallpassL1,allpasstuningL1);
    allpassR[0].setbuffer(bufallpassR1,allpasstuningR1);
    allpassL[1].setbuffer(bufallpassL2,allpasstuningL2);
    allpassR[1].setbuffer(bufallpassR2,allpasstuningR2);
    allpassL[2].setbuffer(bufallpassL3,allpasstuningL3);
    allpassR[2].setbuffer(bufallpassR3,allpasstuningR3);
    allpassL[3].setbuffer(bufallpassL4,allpasstuningL4);
    allpassR[3].setbuffer(bufallpassR4,allpasstuningR4);

    // Set default values
    allpassL[0].setfeedback(0.5f);
    allpassR[0].setfeedback(0.5f);
    allpassL[1].setfeedback(0.5f);
    allpassR[1].setfeedback(0.5f);
    allpassL[2].setfeedback(0.5f);
    allpassR[2].setfeedback(0.5f);
    allpassL[3].setfeedback(0.5f);
    allpassR[3].setfeedback(0.5f);
    setwet(initialwet);
    setroomsize(initialroom);
    setdry(initialdry);
    setdamp(initialdamp);
    setwidth(initialwidth);
    setmode(initialmode);

    // Buffer will be full of rubbish - so we MUST mute them
    mute();
}

void revmodel::mute()
{
    int i;
    if (mode >= freezemode)
        return;

    for (i = 0 ; i < numcombs ; i++)
    {
        combL[i].mute();
        combR[i].mute();
    }
    for (i=0;i<numallpasses;i++)
    {
        allpassL[i].mute();
        allpassR[i].mute();
    }
}

/*****************************************************************************
 *  Transforms the audio stream
 * /param float *inputL     input buffer
 * /param float *outputL   output buffer
 * /param long numsamples  number of samples to be processed
 * /param int skip             number of channels in the audio stream
 *****************************************************************************/
void revmodel::processreplace(float *inputL, float *outputL, long numsamples, int skip)
{
    float outL,outR,input;
    float inputR;
    int i;

    outL = outR = 0;
        /* TODO this module supports only 2 audio channels, let's improve this */
        if (skip > 1)
           inputR = inputL[1];
        else
           inputR = inputL[0];
        input = (inputL[0] + inputR) * gain;

        // Accumulate comb filters in parallel
        for(i=0; i<numcombs; i++)
        {
            outL += combL[i].process(input);
            outR += combR[i].process(input);
        }

        // Feed through allpasses in series
        for(i=0; i<numallpasses; i++)
        {
            outL = allpassL[i].process(outL);
            outR = allpassR[i].process(outR);
        }

        // Calculate output REPLACING anything already there
        outputL[0] = (outL*wet1 + outR*wet2 + inputR*dry);
           if (skip > 1)
        outputL[1] = (outR*wet1 + outL*wet2 + inputR*dry);
}

void revmodel::processmix(float *inputL, float *outputL, long numsamples, int skip)
{
    float outL,outR,input;
    float inputR;
    int i;

    outL = outR = 0;
        if (skip > 1)
           inputR = inputL[1];
        else
           inputR = inputL[0];
        input = (inputL[0] + inputR) * gain;

        // Accumulate comb filters in parallel
        for(i=0; i<numcombs; i++)
        {
            outL += combL[i].process(input);
            outR += combR[i].process(input);
        }

        // Feed through allpasses in series
        for(i=0; i<numallpasses; i++)
        {
            outL = allpassL[i].process(outL);
            outR = allpassR[i].process(outR);
        }

        // Calculate output REPLACING anything already there
        outputL[0] += (outL*wet1 + outR*wet2 + inputR*dry);
           if (skip > 1)
        outputL[1] += (outR*wet1 + outL*wet2 + inputR*dry);
}

void revmodel::update()
{
// Recalculate internal values after parameter change

    int i;

    wet1 = wet*(width/2 + 0.5f);
    wet2 = wet*((1-width)/2);

    if (mode >= freezemode)
    {
        roomsize1 = 1;
        damp1 = 0;
        gain = muted;
    }
    else
    {
        roomsize1 = roomsize;
        damp1 = damp;
        gain = fixedgain;
    }

    for(i=0; i<numcombs; i++)
    {
        combL[i].setfeedback(roomsize1);
        combR[i].setfeedback(roomsize1);
    }

    for(i=0; i<numcombs; i++)
    {
        combL[i].setdamp(damp1);
        combR[i].setdamp(damp1);
    }
}

// The following get/set functions are not inlined, because
// speed is never an issue when calling them, and also
// because as you develop the reverb model, you may
// wish to take dynamic action when they are called.

void revmodel::setroomsize(float value)
{
    roomsize = (value*scaleroom) + offsetroom;
    update();
}

float revmodel::getroomsize()
{
    return (roomsize-offsetroom)/scaleroom;
}

void revmodel::setdamp(float value)
{
    damp = value*scaledamp;
    update();
}

float revmodel::getdamp()
{
    return damp/scaledamp;
}

void revmodel::setwet(float value)
{
    wet = value*scalewet;
    update();
}

float revmodel::getwet()
{
    return wet/scalewet;
}

void revmodel::setdry(float value)
{
    dry = value*scaledry;
}

float revmodel::getdry()
{
    return dry/scaledry;
}

void revmodel::setwidth(float value)
{
    width = value;
    update();
}

float revmodel::getwidth()
{
    return width;
}

void revmodel::setmode(float value)
{
    mode = value;
    update();
}

//ends
<commit_msg>Spatializer: kill warnings and improve locality<commit_after>// Reverb model implementation
//
//
// Google Summer of Code 2007
//
// Authors: Biodun Osunkunle <biodun@videolan.org>
//
// Mentor : Jean-Baptiste Kempf <jb@videolan.org>
//
// Original written by Jezar at Dreampoint, June 2000

// This code is public domain

#include "revmodel.hpp"
#include <stdlib.h>

revmodel::revmodel()
{
    // Tie the components to their buffers
    combL[0].setbuffer(bufcombL1,combtuningL1);
    combR[0].setbuffer(bufcombR1,combtuningR1);
    combL[1].setbuffer(bufcombL2,combtuningL2);
    combR[1].setbuffer(bufcombR2,combtuningR2);
    combL[2].setbuffer(bufcombL3,combtuningL3);
    combR[2].setbuffer(bufcombR3,combtuningR3);
    combL[3].setbuffer(bufcombL4,combtuningL4);
    combR[3].setbuffer(bufcombR4,combtuningR4);
    combL[4].setbuffer(bufcombL5,combtuningL5);
    combR[4].setbuffer(bufcombR5,combtuningR5);
    combL[5].setbuffer(bufcombL6,combtuningL6);
    combR[5].setbuffer(bufcombR6,combtuningR6);
    combL[6].setbuffer(bufcombL7,combtuningL7);
    combR[6].setbuffer(bufcombR7,combtuningR7);
    combL[7].setbuffer(bufcombL8,combtuningL8);
    combR[7].setbuffer(bufcombR8,combtuningR8);
    allpassL[0].setbuffer(bufallpassL1,allpasstuningL1);
    allpassR[0].setbuffer(bufallpassR1,allpasstuningR1);
    allpassL[1].setbuffer(bufallpassL2,allpasstuningL2);
    allpassR[1].setbuffer(bufallpassR2,allpasstuningR2);
    allpassL[2].setbuffer(bufallpassL3,allpasstuningL3);
    allpassR[2].setbuffer(bufallpassR3,allpasstuningR3);
    allpassL[3].setbuffer(bufallpassL4,allpasstuningL4);
    allpassR[3].setbuffer(bufallpassR4,allpasstuningR4);

    // Set default values
    allpassL[0].setfeedback(0.5f);
    allpassR[0].setfeedback(0.5f);
    allpassL[1].setfeedback(0.5f);
    allpassR[1].setfeedback(0.5f);
    allpassL[2].setfeedback(0.5f);
    allpassR[2].setfeedback(0.5f);
    allpassL[3].setfeedback(0.5f);
    allpassR[3].setfeedback(0.5f);
    setwet(initialwet);
    setroomsize(initialroom);
    setdry(initialdry);
    setdamp(initialdamp);
    setwidth(initialwidth);
    setmode(initialmode);

    // Buffer will be full of rubbish - so we MUST mute them
    mute();
}

void revmodel::mute()
{
    int i;
    if (mode >= freezemode)
        return;

    for (i = 0 ; i < numcombs ; i++)
    {
        combL[i].mute();
        combR[i].mute();
    }
    for (i=0;i<numallpasses;i++)
    {
        allpassL[i].mute();
        allpassR[i].mute();
    }
}

/*****************************************************************************
 *  Transforms the audio stream
 * /param float *inputL     input buffer
 * /param float *outputL   output buffer
 * /param long numsamples  number of samples to be processed
 * /param int skip             number of channels in the audio stream
 *****************************************************************************/
void revmodel::processreplace(float *inputL, float *outputL, long /* numsamples */, int skip)
{
    float outL,outR,input;
    float inputR;
    int i;

    outL = outR = 0;
        /* TODO this module supports only 2 audio channels, let's improve this */
        if (skip > 1)
           inputR = inputL[1];
        else
           inputR = inputL[0];
        input = (inputL[0] + inputR) * gain;

        // Accumulate comb filters in parallel
        for(i=0; i<numcombs; i++)
        {
            outL += combL[i].process(input);
            outR += combR[i].process(input);
        }

        // Feed through allpasses in series
        for(i=0; i<numallpasses; i++)
        {
            outL = allpassL[i].process(outL);
            outR = allpassR[i].process(outR);
        }

        // Calculate output REPLACING anything already there
        outputL[0] = (outL*wet1 + outR*wet2 + inputR*dry);
           if (skip > 1)
        outputL[1] = (outR*wet1 + outL*wet2 + inputR*dry);
}

void revmodel::processmix(float *inputL, float *outputL, long /* numsamples */, int skip)
{
    float outL,outR,input;
    float inputR;

    outL = outR = 0;
        if (skip > 1)
           inputR = inputL[1];
        else
           inputR = inputL[0];
        input = (inputL[0] + inputR) * gain;

        // Accumulate comb filters in parallel
        for(int i=0; i<numcombs; i++)
        {
            outL += combL[i].process(input);
            outR += combR[i].process(input);
        }

        // Feed through allpasses in series
        for(int i=0; i<numallpasses; i++)
        {
            outL = allpassL[i].process(outL);
            outR = allpassR[i].process(outR);
        }

        // Calculate output REPLACING anything already there
        outputL[0] += (outL*wet1 + outR*wet2 + inputR*dry);
           if (skip > 1)
        outputL[1] += (outR*wet1 + outL*wet2 + inputR*dry);
}

void revmodel::update()
{
// Recalculate internal values after parameter change

    wet1 = wet*(width/2 + 0.5f);
    wet2 = wet*((1-width)/2);

    if (mode >= freezemode)
    {
        roomsize1 = 1;
        damp1 = 0;
        gain = muted;
    }
    else
    {
        roomsize1 = roomsize;
        damp1 = damp;
        gain = fixedgain;
    }

    for(int i=0; i<numcombs; i++)
    {
        combL[i].setfeedback(roomsize1);
        combR[i].setfeedback(roomsize1);
    }

    for(int i=0; i<numcombs; i++)
    {
        combL[i].setdamp(damp1);
        combR[i].setdamp(damp1);
    }
}

// The following get/set functions are not inlined, because
// speed is never an issue when calling them, and also
// because as you develop the reverb model, you may
// wish to take dynamic action when they are called.

void revmodel::setroomsize(float value)
{
    roomsize = (value*scaleroom) + offsetroom;
    update();
}

float revmodel::getroomsize()
{
    return (roomsize-offsetroom)/scaleroom;
}

void revmodel::setdamp(float value)
{
    damp = value*scaledamp;
    update();
}

float revmodel::getdamp()
{
    return damp/scaledamp;
}

void revmodel::setwet(float value)
{
    wet = value*scalewet;
    update();
}

float revmodel::getwet()
{
    return wet/scalewet;
}

void revmodel::setdry(float value)
{
    dry = value*scaledry;
}

float revmodel::getdry()
{
    return dry/scaledry;
}

void revmodel::setwidth(float value)
{
    width = value;
    update();
}

float revmodel::getwidth()
{
    return width;
}

void revmodel::setmode(float value)
{
    mode = value;
    update();
}

//ends
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include "cubeproxygeometry.h"
#include <inviwo/core/datastructures/geometry/simplemeshcreator.h>
#include <inviwo/core/network/networklock.h>

namespace inviwo {

const ProcessorInfo CubeProxyGeometry::processorInfo_{
    "org.inviwo.CubeProxyGeometry",  // Class identifier
    "Cube Proxy Geometry",           // Display name
    "Geometry Creation",             // Category
    CodeState::Stable,               // Code state
    Tags::CPU,                       // Tags
};
const ProcessorInfo CubeProxyGeometry::getProcessorInfo() const {
    return processorInfo_;
}

CubeProxyGeometry::CubeProxyGeometry()
    : Processor()
    , inport_("volume")
    , outport_("proxyGeometry")
    , clippingEnabled_("clippingEnabled", "Enable Clipping", true)
    , clipX_("clipX", "Clip X Slices", 0, 256, 0, 256, 1, 1)
    , clipY_("clipY", "Clip Y Slices", 0, 256, 0, 256, 1, 1)
    , clipZ_("clipZ", "Clip Z Slices", 0, 256, 0, 256, 1, 1) {

    addPort(inport_);
    addPort(outport_);
    addProperty(clippingEnabled_);
    addProperty(clipX_);
    addProperty(clipY_);
    addProperty(clipZ_);

    // Since the clips depend on the input volume dimensions, we make sure to always
    // serialize them so we can do a proper renormalization when we load new data.
    clipX_.setSerializationMode(PropertySerializationMode::All);
    clipY_.setSerializationMode(PropertySerializationMode::All);
    clipZ_.setSerializationMode(PropertySerializationMode::All);

    inport_.onChange(this, &CubeProxyGeometry::onVolumeChange);
}

CubeProxyGeometry::~CubeProxyGeometry() {}

void CubeProxyGeometry::process() {
    vec3 startDataTexCoord = vec3(0.0f);
    vec3 extent = vec3(1.0f); //!< will be added to the origin in the parallelepiped() yielding the end position

    if (inport_.getData()->getMetaData<BoolMetaData>("marginsEnabled", false)) {
        // volume has margins enabled
        // adjust start and end texture coordinate accordingly
        auto marginsBottomLeft = inport_.getData()->getMetaData<FloatVec3MetaData>("marginsBottomLeft", vec3(0.0f));
        auto marginsTopRight = inport_.getData()->getMetaData<FloatVec3MetaData>("marginsTopRight", vec3(0.0f));

        startDataTexCoord += marginsBottomLeft;
        // extent needs to be adjusted for both margins
        extent -= marginsBottomLeft + marginsTopRight;
    }

    glm::vec3 pos(0.0f);
    glm::vec3 p1(1.0f, 0.0f, 0.0f);
    glm::vec3 p2(0.0f, 1.0f, 0.0f);
    glm::vec3 p3(0.0f, 0.0f, 1.0f);
    glm::vec3 tex(startDataTexCoord);
    glm::vec3 t1(extent.x, 0.0f, 0.0f);
    glm::vec3 t2(0.0f, extent.y, 0.0f);
    glm::vec3 t3(0.0f, 0.0f, extent.z);
    glm::vec4 col(startDataTexCoord, 1.0f);
    glm::vec4 c1(t1, 0.0f);
    glm::vec4 c2(t2, 0.0f);
    glm::vec4 c3(t3, 0.0f);
    auto dims = inport_.getData()->getDimensions();

    if (clippingEnabled_.get()) {
        pos = pos + p1*static_cast<float>(clipX_.get().x)/static_cast<float>(dims.x)
                  + p2*static_cast<float>(clipY_.get().x)/static_cast<float>(dims.y)
                  + p3*static_cast<float>(clipZ_.get().x)/static_cast<float>(dims.z);
        p1 = p1*(static_cast<float>(clipX_.get().y)-static_cast<float>(clipX_.get().x))/static_cast<float>(dims.x);
        p2 = p2*(static_cast<float>(clipY_.get().y)-static_cast<float>(clipY_.get().x))/static_cast<float>(dims.y);
        p3 = p3*(static_cast<float>(clipZ_.get().y)-static_cast<float>(clipZ_.get().x))/static_cast<float>(dims.z);
        tex = tex + t1*static_cast<float>(clipX_.get().x)/static_cast<float>(dims.x)
                  + t2*static_cast<float>(clipY_.get().x)/static_cast<float>(dims.y)
                  + t3*static_cast<float>(clipZ_.get().x)/static_cast<float>(dims.z);
        t1 = t1*(static_cast<float>(clipX_.get().y)-static_cast<float>(clipX_.get().x))/static_cast<float>(dims.x);
        t2 = t2*(static_cast<float>(clipY_.get().y)-static_cast<float>(clipY_.get().x))/static_cast<float>(dims.y);
        t3 = t3*(static_cast<float>(clipZ_.get().y)-static_cast<float>(clipZ_.get().x))/static_cast<float>(dims.z);
        col = col + c1*static_cast<float>(clipX_.get().x)/static_cast<float>(dims.x)
                  + c2*static_cast<float>(clipY_.get().x)/static_cast<float>(dims.y)
                  + c3*static_cast<float>(clipZ_.get().x)/static_cast<float>(dims.z);
        c1 = c1*(static_cast<float>(clipX_.get().y)-static_cast<float>(clipX_.get().x))/static_cast<float>(dims.x);
        c2 = c2*(static_cast<float>(clipY_.get().y)-static_cast<float>(clipY_.get().x))/static_cast<float>(dims.y);
        c3 = c3*(static_cast<float>(clipZ_.get().y)-static_cast<float>(clipZ_.get().x))/static_cast<float>(dims.z);
    }

    // Create parallelepiped and set it to the outport. The outport will own the data.
    auto geom = SimpleMeshCreator::parallelepiped(pos, p1, p2, p3,
                                                  tex, t1, t2, t3,
                                                  col, c1, c2, c3);
    geom->setModelMatrix(inport_.getData()->getModelMatrix());
    geom->setWorldMatrix(inport_.getData()->getWorldMatrix());
    outport_.setData(geom);
}

void CubeProxyGeometry::onVolumeChange() {
    // Update to the new dimensions.
    auto dims = inport_.getData()->getDimensions();
    if (dims != size3_t(clipX_.getRangeMax(), clipY_.getRangeMax(), clipZ_.getRangeMax())) {
        NetworkLock lock(this);

        clipX_.setRangeNormalized(ivec2(0, dims.x));
        clipY_.setRangeNormalized(ivec2(0, dims.y));
        clipZ_.setRangeNormalized(ivec2(0, dims.z));

        // set the new dimensions to default if we were to press reset
        clipX_.setCurrentStateAsDefault();
        clipY_.setCurrentStateAsDefault();
        clipZ_.setCurrentStateAsDefault();
    }

}

} // namespace

<commit_msg>Base: cleanup in CubeProxyGeometry<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include "cubeproxygeometry.h"
#include <inviwo/core/datastructures/geometry/simplemeshcreator.h>
#include <inviwo/core/network/networklock.h>

namespace inviwo {

const ProcessorInfo CubeProxyGeometry::processorInfo_{
    "org.inviwo.CubeProxyGeometry",  // Class identifier
    "Cube Proxy Geometry",           // Display name
    "Geometry Creation",             // Category
    CodeState::Stable,               // Code state
    Tags::CPU,                       // Tags
};
const ProcessorInfo CubeProxyGeometry::getProcessorInfo() const {
    return processorInfo_;
}

CubeProxyGeometry::CubeProxyGeometry()
    : Processor()
    , inport_("volume")
    , outport_("proxyGeometry")
    , clippingEnabled_("clippingEnabled", "Enable Clipping", true)
    , clipX_("clipX", "Clip X Slices", 0, 256, 0, 256, 1, 1)
    , clipY_("clipY", "Clip Y Slices", 0, 256, 0, 256, 1, 1)
    , clipZ_("clipZ", "Clip Z Slices", 0, 256, 0, 256, 1, 1) {

    addPort(inport_);
    addPort(outport_);
    addProperty(clippingEnabled_);
    addProperty(clipX_);
    addProperty(clipY_);
    addProperty(clipZ_);

    // Since the clips depend on the input volume dimensions, we make sure to always
    // serialize them so we can do a proper renormalization when we load new data.
    clipX_.setSerializationMode(PropertySerializationMode::All);
    clipY_.setSerializationMode(PropertySerializationMode::All);
    clipZ_.setSerializationMode(PropertySerializationMode::All);

    inport_.onChange(this, &CubeProxyGeometry::onVolumeChange);
}

CubeProxyGeometry::~CubeProxyGeometry() {}

void CubeProxyGeometry::process() {
    vec3 startDataTexCoord = vec3(0.0f);
    vec3 extent = vec3(1.0f); //!< will be added to the origin in the parallelepiped() yielding the end position

    if (inport_.getData()->getMetaData<BoolMetaData>("marginsEnabled", false)) {
        // volume has margins enabled
        // adjust start and end texture coordinate accordingly
        auto marginsBottomLeft = inport_.getData()->getMetaData<FloatVec3MetaData>("marginsBottomLeft", vec3(0.0f));
        auto marginsTopRight = inport_.getData()->getMetaData<FloatVec3MetaData>("marginsTopRight", vec3(0.0f));

        startDataTexCoord += marginsBottomLeft;
        // extent needs to be adjusted for both margins
        extent -= marginsBottomLeft + marginsTopRight;
    }

    glm::vec3 origin(0.0f);
    glm::vec3 e1(1.0f, 0.0f, 0.0f);
    glm::vec3 e2(0.0f, 1.0f, 0.0f);
    glm::vec3 e3(0.0f, 0.0f, 1.0f);
    glm::vec3 texOrigin(startDataTexCoord);
    glm::vec3 t1(extent.x, 0.0f, 0.0f);
    glm::vec3 t2(0.0f, extent.y, 0.0f);
    glm::vec3 t3(0.0f, 0.0f, extent.z);
    glm::vec4 colOrigin(startDataTexCoord, 1.0f);
    glm::vec4 c1(t1, 0.0f);
    glm::vec4 c2(t2, 0.0f);
    glm::vec4 c3(t3, 0.0f);
    auto dims = inport_.getData()->getDimensions();

    if (clippingEnabled_.get()) {
        vec3 clipMin(clipX_.get().x, clipY_.get().x, clipZ_.get().x);
        vec3 clipMax(clipX_.get().y, clipY_.get().y, clipZ_.get().y);

        vec3 min(clipMin / vec3(dims));
        vec3 extent((clipMax - clipMin) / vec3(dims));

        origin = origin + e1 * min.x + e2 * min.y + e3 * min.z;
        e1 *= extent.x;
        e2 *= extent.y;
        e3 *= extent.z;

        texOrigin = texOrigin + t1 * min.x + t2 * min.y + t3 * min.z;
        t1 *= extent.x;
        t2 *= extent.y;
        t3 *= extent.z;

        colOrigin += c1 * min.x + c2 * min.y + c3 * min.z;
        c1 *= extent.x;
        c2 *= extent.y;
        c3 *= extent.z;
    }

    // Create parallelepiped and set it to the outport. The outport will own the data.
    auto geom = SimpleMeshCreator::parallelepiped(origin, e1, e2, e3,
                                                  texOrigin, t1, t2, t3,
                                                  colOrigin, c1, c2, c3);
    geom->setModelMatrix(inport_.getData()->getModelMatrix());
    geom->setWorldMatrix(inport_.getData()->getWorldMatrix());
    outport_.setData(geom);
}

void CubeProxyGeometry::onVolumeChange() {
    // Update to the new dimensions.
    auto dims = inport_.getData()->getDimensions();
    if (dims != size3_t(clipX_.getRangeMax(), clipY_.getRangeMax(), clipZ_.getRangeMax())) {
        NetworkLock lock(this);

        clipX_.setRangeNormalized(ivec2(0, dims.x));
        clipY_.setRangeNormalized(ivec2(0, dims.y));
        clipZ_.setRangeNormalized(ivec2(0, dims.z));

        // set the new dimensions to default if we were to press reset
        clipX_.setCurrentStateAsDefault();
        clipY_.setCurrentStateAsDefault();
        clipZ_.setCurrentStateAsDefault();
    }

}

} // namespace

<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright( C) 2000-2015, Intel Corporation, all rights reserved.
// Copyright (C) 2011-2013, NVIDIA Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Copyright (C) 2015, Itseez Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
//(including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort(including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

/*
  definition of the current version of OpenCV
  Usefull to test in user programs
*/

#ifndef OPENCV_VERSION_HPP
#define OPENCV_VERSION_HPP

#define CV_VERSION_MAJOR    3
#define CV_VERSION_MINOR    2
#define CV_VERSION_REVISION 0
#define CV_VERSION_STATUS   "-dev"

#define CVAUX_STR_EXP(__A)  #__A
#define CVAUX_STR(__A)      CVAUX_STR_EXP(__A)

#define CVAUX_STRW_EXP(__A)  L ## #__A
#define CVAUX_STRW(__A)      CVAUX_STRW_EXP(__A)

#define CV_VERSION          CVAUX_STR(CV_VERSION_MAJOR) "." CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(CV_VERSION_REVISION) CV_VERSION_STATUS

/* old  style version constants*/
#define CV_MAJOR_VERSION    CV_VERSION_MAJOR
#define CV_MINOR_VERSION    CV_VERSION_MINOR
#define CV_SUBMINOR_VERSION CV_VERSION_REVISION

#endif
<commit_msg>version 3.3.0-rc<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                        Intel License Agreement
//                For Open Source Computer Vision Library
//
// Copyright( C) 2000-2015, Intel Corporation, all rights reserved.
// Copyright (C) 2011-2013, NVIDIA Corporation, all rights reserved.
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Copyright (C) 2015, Itseez Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of Intel Corporation may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
//(including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort(including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

/*
  definition of the current version of OpenCV
  Usefull to test in user programs
*/

#ifndef OPENCV_VERSION_HPP
#define OPENCV_VERSION_HPP

#define CV_VERSION_MAJOR    3
#define CV_VERSION_MINOR    3
#define CV_VERSION_REVISION 0
#define CV_VERSION_STATUS   "-rc"

#define CVAUX_STR_EXP(__A)  #__A
#define CVAUX_STR(__A)      CVAUX_STR_EXP(__A)

#define CVAUX_STRW_EXP(__A)  L ## #__A
#define CVAUX_STRW(__A)      CVAUX_STRW_EXP(__A)

#define CV_VERSION          CVAUX_STR(CV_VERSION_MAJOR) "." CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(CV_VERSION_REVISION) CV_VERSION_STATUS

/* old  style version constants*/
#define CV_MAJOR_VERSION    CV_VERSION_MAJOR
#define CV_MINOR_VERSION    CV_VERSION_MINOR
#define CV_SUBMINOR_VERSION CV_VERSION_REVISION

#endif
<|endoftext|>


<commit_before>
/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

// Sanity check integration test for registry
// Spec file: specs/windows/registry.table

#include <osquery/tests/integration/tables/helper.h>

namespace osquery {

class registry : public IntegrationTableTest {};

TEST_F(registry, test_sanity) {
  // 1. Query data
  // QueryData data = execute_query("select * from registry");
  // 2. Check size before validation
  // ASSERT_GE(data.size(), 0ul);
  // ASSERT_EQ(data.size(), 1ul);
  // ASSERT_EQ(data.size(), 0ul);
  // 3. Build validation map
  // See IntegrationTableTest.cpp for avaialbe flags
  // Or use custom DataCheck object
  // ValidatatioMap row_map = {
  //      {"key", NormalType}
  //      {"path", NormalType}
  //      {"name", NormalType}
  //      {"type", NormalType}
  //      {"data", NormalType}
  //      {"mtime", IntType}
  //}
  // 4. Perform validation
  // validate_rows(data, row_map);
}

} // namespace osquery
<commit_msg>[Table sanity check] Integration test for the `registry` table (#5155)<commit_after>
/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

// Sanity check integration test for registry
// Spec file: specs/windows/registry.table

#include <osquery/tests/integration/tables/helper.h>

namespace osquery {
namespace {

class RegistryTest : public IntegrationTableTest {};

TEST_F(RegistryTest, sanity) {
  QueryData const rows = execute_query("select * from registry");
  ASSERT_GT(rows.size(), 0ul);
  auto const row_map = ValidatatioMap{
      {"key", NonEmptyString},
      {"path", NonEmptyString},
      {"name", NonEmptyString},
      {"type", NonEmptyString},
      {"data", NormalType},
      {"mtime", NonNegativeInt},
  };
  validate_rows(rows, row_map);
}

} // namespace
} // namespace osquery
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* 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.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "rhodes/JNIRhodes.h"
#include "rhodes/JNIRhoRuby.h"

#include "rhodes/jni/com_rhomobile_rhodes_signature_Signature.h"

#include <common/rhoparams.h>
#include <common/RhodesApp.h>
#include <logging/RhoLog.h>
#include "ruby/ext/rho/rhoruby.h"

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "Signature"

RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_signature_Signature_callback
  (JNIEnv *env, jclass, jstring callback, jstring filePath, jstring error, jboolean cancelled)
{
    rho_rhodesapp_callSignatureCallback(rho_cast<std::string>(callback).c_str(),
        rho_cast<std::string>(filePath).c_str(), rho_cast<std::string>(error).c_str(), cancelled);
}

RHO_GLOBAL void rho_signature_take(char* callback_url, rho_param* p)
{

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "takeSignature", "(Ljava/lang/String;Ljava/lang/Object;)V");
    if (!mid) return;
    jhstring objCallback = rho_cast<jhstring>(callback_url);

    /*
    char* image_format = 0;
    if (p)
    {
        rho_param* pFF = rho_param_hash_get(p, "imageFormat");
        if ( pFF )
            image_format = pFF->v.string;
    }
    if (!image_format)
        image_format = "";

    jhstring objFormat = rho_cast<jhstring>(image_format);
    env->CallStaticVoidMethod(cls, mid, objCallback.get(), objFormat.get());
     */

    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(cls, mid, objCallback.get(), paramsObj);
    env->DeleteLocalRef(paramsObj);

}

RHO_GLOBAL void rho_signature_visible(bool visible, rho_param* p)
{
    // check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
    if (!rho_is_rho_elements_extension_can_be_used()) {
        RAWLOG_ERROR("Rho::SignatureCapture.visible() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
        return;
    }
#endif
#endif

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "inline_signature_visible", "(ILjava/lang/Object;)V");
    if (!mid) return;

    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(cls, mid, visible, paramsObj);
    env->DeleteLocalRef(paramsObj);
}

RHO_GLOBAL void rho_signature_capture(const char* callback_url)
{
    // check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
    if (!rho_is_rho_elements_extension_can_be_used()) {
        RAWLOG_ERROR("Rho::SignatureCapture.capture() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
        return;
    }
#endif
#endif

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "inline_signature_capture", "(Ljava/lang/String;)V");
    if (!mid) return;
    jhstring objCallback = rho_cast<jhstring>(callback_url);

    env->CallStaticVoidMethod(cls, mid, objCallback.get());

}

RHO_GLOBAL void rho_signature_clear()
{
    // check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
    if (!rho_is_rho_elements_extension_can_be_used()) {
        RAWLOG_ERROR("Rho::SignatureCapture.clear() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
        return;
    }
#endif
#endif

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "inline_signature_clear", "()V");
    if (!mid) return;
    env->CallStaticVoidMethod(cls, mid);

}
<commit_msg>Android: fix licanse checking removal for inline signature capture in case of motorola<commit_after>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* 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.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "rhodes/JNIRhodes.h"
#include "rhodes/JNIRhoRuby.h"

#include "rhodes/jni/com_rhomobile_rhodes_signature_Signature.h"

#include "common/app_build_capabilities.h"
#include "common/rhoparams.h"
#include "common/RhodesApp.h"
#include "logging/RhoLog.h"
#include "ruby/ext/rho/rhoruby.h"

#undef DEFAULT_LOGCATEGORY
#define DEFAULT_LOGCATEGORY "Signature"

RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_signature_Signature_callback
  (JNIEnv *env, jclass, jstring callback, jstring filePath, jstring error, jboolean cancelled)
{
    rho_rhodesapp_callSignatureCallback(rho_cast<std::string>(callback).c_str(),
        rho_cast<std::string>(filePath).c_str(), rho_cast<std::string>(error).c_str(), cancelled);
}

RHO_GLOBAL void rho_signature_take(char* callback_url, rho_param* p)
{

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "takeSignature", "(Ljava/lang/String;Ljava/lang/Object;)V");
    if (!mid) return;
    jhstring objCallback = rho_cast<jhstring>(callback_url);

    /*
    char* image_format = 0;
    if (p)
    {
        rho_param* pFF = rho_param_hash_get(p, "imageFormat");
        if ( pFF )
            image_format = pFF->v.string;
    }
    if (!image_format)
        image_format = "";

    jhstring objFormat = rho_cast<jhstring>(image_format);
    env->CallStaticVoidMethod(cls, mid, objCallback.get(), objFormat.get());
     */

    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(cls, mid, objCallback.get(), paramsObj);
    env->DeleteLocalRef(paramsObj);

}

RHO_GLOBAL void rho_signature_visible(bool visible, rho_param* p)
{
    // check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
    if (!rho_is_rho_elements_extension_can_be_used()) {
        RAWLOG_ERROR("Rho::SignatureCapture.visible() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
        return;
    }
#endif
#endif

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "inline_signature_visible", "(ILjava/lang/Object;)V");
    if (!mid) return;

    jobject paramsObj = RhoValueConverter(env).createObject(p);
    env->CallStaticVoidMethod(cls, mid, visible, paramsObj);
    env->DeleteLocalRef(paramsObj);
}

RHO_GLOBAL void rho_signature_capture(const char* callback_url)
{
    // check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
    if (!rho_is_rho_elements_extension_can_be_used()) {
        RAWLOG_ERROR("Rho::SignatureCapture.capture() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
        return;
    }
#endif
#endif

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "inline_signature_capture", "(Ljava/lang/String;)V");
    if (!mid) return;
    jhstring objCallback = rho_cast<jhstring>(callback_url);

    env->CallStaticVoidMethod(cls, mid, objCallback.get());

}

RHO_GLOBAL void rho_signature_clear()
{
    // check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
    if (!rho_is_rho_elements_extension_can_be_used()) {
        RAWLOG_ERROR("Rho::SignatureCapture.clear() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
        return;
    }
#endif
#endif

    JNIEnv *env = jnienv();
    jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
    if (!cls) return;
    jmethodID mid = getJNIClassStaticMethod(env, cls, "inline_signature_clear", "()V");
    if (!mid) return;
    env->CallStaticVoidMethod(cls, mid);

}
<|endoftext|>


<commit_before>#define DEBUG 0
/**
 * File    : H.cpp
 * Author  : Kazune Takahashi
 * Created : 2019/12/30 18:11:35
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
// ----- boost -----
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using boost::rational;
using namespace std;
using ll = long long;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{x % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- PrimeNums -----

class PrimeNums
{
  static constexpr ll MAX_SIZE{1000010LL};
  ll N;
  vector<bool> isprime;
  vector<int> prime_nums;

public:
  PrimeNums(ll N = MAX_SIZE) : N{N}, isprime(N, true), prime_nums{}
  {
    isprime[0] = isprime[1] = false;
    for (auto i = 2; i < N; i++)
    {
      if (isprime[i])
      {
        prime_nums.push_back(i);
        for (auto j = 2 * i; j < N; j += i)
        {
          isprime[j] = false;
        }
      }
    }
  }

  bool is_prime(long long x)
  { // 2 \leq x \leq MAX_SIZE^2
    if (x < N)
    {
      return isprime[x];
    }
    for (auto e : prime_nums)
    {
      if (x % e == 0)
        return false;
    }
    return true;
  }

  vector<int> const &primes() const
  {
    return prime_nums;
  }
};

// ----- main() -----
class Solve
{
  int H, W;
  vector<string> S;
  PrimeNums pn;

public:
  Solve(int H, int W, vector<string> const &S) : H{H}, W{W}, S(S), pn{} {}

  int calc()
  {
    int ans{0};
    for (auto i = 0; i < H; i++)
    {
      ans += calc(S[i]);
    }
    return ans;
  };

private:
  int calc(string const &T)
  {
    if (is_zero(T))
    {
      return 0;
    }
    auto V{make_vec(T)};
    if (is_one(V))
    {
      return 1;
    }
    if (is_two(V))
    {
      return 2;
    }
    return 3;
  }

  bool is_zero(string const &T)
  {
    for (auto x : T)
    {
      if (x == '.')
      {
        return false;
      }
    }
    return true;
  }

  vector<int> make_vec(string const &T)
  {
    int first{-1};
    vector<int> V;
    for (auto i = 0; i < W; i++)
    {
      if (T[i] == '.')
      {
        if (first == -1)
        {
          first = i;
        }
        V.push_back(i - first);
      }
    }
    return V;
  }

  bool is_one(vector<int> const &V)
  {
    if (V.size() < size_t{2})
    {
      return true;
    }
    assert(V[0] == 0);
    int g{V[1]};
    for (auto it = V.begin() + 1; it != V.end(); it++)
    {
      g = gcd(g, *it);
    }
    for (auto i = 0; i < 20; i++)
    {
      if (g == 1 << i)
      {
        return false;
      }
    }
    return true;
  }

  bool is_two(vector<int> const &V)
  {
    int X{static_cast<int>(V.size())};
    if (X <= 1)
    {
      assert(false);
      return false;
    }
    if (X == 2)
    {
      return true;
    }
    for (auto it = pn.primes().begin() + 1; it != pn.primes().end(); it++)
    {
      int p{static_cast<int>(*it)};
      if (W * 2 + 3 < X * p)
      {
        return false;
      }
      vector<set<int>> E(p);
      for (auto x : V)
      {
        E[x % p].insert(x);
      }
      for (auto k = 0; k < p; k++)
      {
        if (E[k].size() < X / 2)
        {
          continue;
        }
        int first{-1};
        vector<int> W;
        for (auto x : V)
        {
          if (E[k].find(x) != E[k].end())
          {
            continue;
          }
          if (first == -1)
          {
            first = x;
          }
          W.push_back(x - first);
        }
        if (is_one(W))
        {
          return true;
        }
      }
    }
    assert(false);
    return false;
  }
};

int main()
{
  int H, W;
  cin >> H >> W;
  vector<string> S(H);
  for (auto i = 0; i < H; i++)
  {
    cin >> S[i];
  }
  Solve solve(H, W, S);
  cout << solve.calc() << endl;
}
<commit_msg>submit H.cpp to 'H - Stamps 3' (xmascon19) [C++14 (GCC 5.4.1)]<commit_after>#define DEBUG 0
/**
 * File    : H.cpp
 * Author  : Kazune Takahashi
 * Created : 2019/12/30 18:11:35
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
// ----- boost -----
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using boost::rational;
using namespace std;
using ll = long long;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{x % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- PrimeNums -----

class PrimeNums
{
  static constexpr ll MAX_SIZE{1000010LL};
  ll N;
  vector<bool> isprime;
  vector<int> prime_nums;

public:
  PrimeNums(ll N = MAX_SIZE) : N{N}, isprime(N, true), prime_nums{}
  {
    isprime[0] = isprime[1] = false;
    for (auto i = 2; i < N; i++)
    {
      if (isprime[i])
      {
        prime_nums.push_back(i);
        for (auto j = 2 * i; j < N; j += i)
        {
          isprime[j] = false;
        }
      }
    }
  }

  bool is_prime(long long x)
  { // 2 \leq x \leq MAX_SIZE^2
    if (x < N)
    {
      return isprime[x];
    }
    for (auto e : prime_nums)
    {
      if (x % e == 0)
        return false;
    }
    return true;
  }

  vector<int> const &primes() const
  {
    return prime_nums;
  }
};

// ----- main() -----
class Solve
{
  int H, W;
  vector<string> S;
  PrimeNums pn;

public:
  Solve(int H, int W, vector<string> const &S) : H{H}, W{W}, S(S), pn{} {}

  int calc()
  {
    int ans{0};
    for (auto i = 0; i < H; i++)
    {
      ans += calc(S[i]);
    }
    return ans;
  };

private:
  int calc(string const &T)
  {
    if (is_zero(T))
    {
      return 0;
    }
    auto V{make_vec(T)};
    if (is_one(V))
    {
      return 1;
    }
    if (is_two(V))
    {
      return 2;
    }
    return 3;
  }

  bool is_zero(string const &T)
  {
    for (auto x : T)
    {
      if (x == '.')
      {
        return false;
      }
    }
    return true;
  }

  vector<int> make_vec(string const &T)
  {
    int first{-1};
    vector<int> V;
    for (auto i = 0; i < W; i++)
    {
      if (T[i] == '.')
      {
        if (first == -1)
        {
          first = i;
        }
        V.push_back(i - first);
      }
    }
    return V;
  }

  bool is_one(vector<int> const &V)
  {
    if (V.size() < size_t{2})
    {
      return true;
    }
    assert(V[0] == 0);
    int g{V[1]};
    for (auto it = V.begin() + 1; it != V.end(); it++)
    {
      g = gcd(g, *it);
    }
    for (auto i = 0; i < 20; i++)
    {
      if (g == 1 << i)
      {
        return false;
      }
    }
    return true;
  }

  bool is_two(vector<int> const &V)
  {
    int X{static_cast<int>(V.size())};
    if (X <= 1)
    {
      assert(false);
      return false;
    }
    if (X == 2)
    {
      return true;
    }
    if (X == 3)
    {
      for (auto k = 0; k < 3; k++)
      {
        int first = -1;
        vector<int> W;
        for (auto i = 0; i < 3; i++)
        {
          if (i != k)
          {
            if (first == -1)
            {
              first = V[i];
            }
            W.push_back(V[i] - first);
          }
        }
        if (is_one(W))
        {
          return true;
        }
      }
      return false;
    }
    for (auto it = pn.primes().begin() + 1; it != pn.primes().end(); it++)
    {
      int p{static_cast<int>(*it)};
      if (2 * W + 3 < p * X)
      {
        return false;
      }
      vector<int> M;
      M.push_back(0);
      for (auto i = 1; i < X; i++)
      {
        if (V[i] % p == 0)
        {
          continue;
        }
        M.push_back(V[i]);
        break;
      }
      for (auto m : M)
      {
        int first{-1};
        vector<int> W;
        for (auto x : V)
        {
          if ((x - m) % p == 0)
          {
            continue;
          }
          if (first == -1)
          {
            first = x;
          }
          W.push_back(x - first);
        }
        if (is_one(W))
        {
          return true;
        }
      }
    }
    assert(false);
    return false;
  }
};

int main()
{
  int H, W;
  cin >> H >> W;
  vector<string> S(H);
  for (auto i = 0; i < H; i++)
  {
    cin >> S[i];
  }
  Solve solve(H, W, S);
  cout << solve.calc() << endl;
}
<|endoftext|>


<commit_before>#include <SDL/SDL.h>
#include <glm/gtx/fast_square_root.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Terrain.h"

#define vindex(x, z) (3 * ((z) * x_res + x))
#define vecx(x, z) vertex_data[vindex(x,z)]
#define vecy(x, z) vertex_data[vindex(x,z)+1]
#define vecz(x, z) vertex_data[vindex(x,z)+2]

Terrain::Terrain(const char *hmap_path, GLfloat vertical_scaling)
{
	SDL_Surface *heightmap = SDL_LoadBMP(hmap_path);
	if (!heightmap) {
		printf("Could not read terrain map %s\n", hmap_path);
		vertex_data = NULL;
		index_data = NULL;
		x_res = z_res = 0;
		return;
	}

	this->vertical_scaling = vertical_scaling;
	x_res = heightmap->w;
	z_res = heightmap->h;
	// Assume 8-bit data
	unsigned char *data = (unsigned char*)heightmap->pixels;

	allocCount(x_res * z_res, (x_res - 1) * (z_res - 1) * 2);

	// Load vertex coordinates and uv data
	for (int z = 0; z < z_res; z++)
		for (int x = 0; x < x_res; x++) {
			// Vertex coords
			unsigned int index_low = vindex(x, z);
			vertex_data[index_low] = (GLfloat)x - ((GLfloat)x_res / 2.0f);
			vertex_data[index_low+1] = (GLfloat)(data[z * x_res + x]) * vertical_scaling / 256.0f;
			vertex_data[index_low+2] = (GLfloat)z - ((GLfloat)z_res / 2.0f);

			// Vertex UV
			unsigned int uv_index_low = 2 * (z * x_res + x);
			uv_data[uv_index_low] = z % 2 ? 0.0f : 1.0f;
			uv_data[uv_index_low+1] = x % 2 ? 0.0f : 1.0f;
		}

	// Generate triangle indices
	for (int z = 0; z < (z_res - 1); z++)
		for (int x = 0; x < (x_res - 1); x++) {
			unsigned int index_low = 6 * (z * (x_res - 1) + x);

			index_data[index_low+0] = z * x_res + x + 1;
			index_data[index_low+1] = z * x_res + x;
			index_data[index_low+2] = (z+1) * x_res + x + 1;

			index_data[index_low+3] = z * x_res + x;
			index_data[index_low+4] = (z+1) * x_res + x;
			index_data[index_low+5] = (z+1) * x_res + x + 1;
		}

	// Compute normals
	for (int z = 1; z < (z_res - 1); z++)
		for (int x = 1; x < (x_res - 1); x++) {
			// coordinates of neighbour vertices
			glm::vec3 mid(vecx(x,z), vecy(x,z), vecz(x,z)),
				west(vecx(x-1,z), vecy(x-1,z), vecz(x-1,z)),
				north(vecx(x,z+1), vecy(x,z+1), vecz(x,z+1)),
				east(vecx(x+1,z), vecy(x+1,z), vecz(x+1,z)),
				south(vecx(x,z-1), vecy(x,z-1), vecz(x,z-1));

			// average face normals for a smooth vertex normal
			glm::vec3 triangle_normal_acc;
			triangle_normal_acc = glm::fastNormalize(glm::cross(mid - north, west - north));
			triangle_normal_acc += glm::fastNormalize(glm::cross(mid - east, north - east));
			triangle_normal_acc += glm::fastNormalize(glm::cross(mid - south, east - south));
			triangle_normal_acc += glm::fastNormalize(glm::cross(mid - west, south - west));
			triangle_normal_acc *= 0.25f;

			memcpy(&normal_data[vindex(x,z)], (float*)glm::value_ptr(triangle_normal_acc), sizeof(float)*3);
		}

	syncBuffers();
	SDL_FreeSurface(heightmap);

	Material *m = new Material();
	m->ambient = glm::vec4(0.5f, 0.5f, 0.5f, 1.0f);
	//m->ambient = glm::vec4(0,0,0,1);
	m->diffuse = glm::vec4(1.0f);
	m->texture = new Texture("textures/ground.bmp");
	setMaterial(m);
}

Terrain::~Terrain()
{
	free(vertex_data);
	free(index_data);
}

/// Returns interpolated height for the given (x,z) coordinates.
// The coordinates are in object space, (0,0) beeing the center.
GLfloat Terrain::getHeight(GLfloat x, GLfloat z)
{
	int ix = (int)floor(x) + x_res / 2;
	int iz = (int)floor(z) + z_res / 2;

	// check boundaries
	if (
			(ix < 0) ||
			((ix+1) >= x_res) ||
			(iz < 0) ||
			((iz+1) >= z_res))
		return 0.0f;

	float dx = x - floor(x);
	float dz = z - floor(z);

	// bilinear interpolation of height values
	float h0 = (1.0f - dx) * vecy(ix,iz) + dx * vecy(ix+1, iz);
	float h1 = (1.0f - dx) * vecy(ix,iz+1) + dx * vecy(ix+1, iz+1);
	return (1.0f - dz) * h0 + dz * h1;
}

<commit_msg>Fixes Terrain cleanup.<commit_after>#include <SDL/SDL.h>
#include <glm/gtx/fast_square_root.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Terrain.h"

#define vindex(x, z) (3 * ((z) * x_res + x))
#define vecx(x, z) vertex_data[vindex(x,z)]
#define vecy(x, z) vertex_data[vindex(x,z)+1]
#define vecz(x, z) vertex_data[vindex(x,z)+2]

Terrain::Terrain(const char *hmap_path, GLfloat vertical_scaling)
{
	SDL_Surface *heightmap = SDL_LoadBMP(hmap_path);
	if (!heightmap) {
		printf("Could not read terrain map %s\n", hmap_path);
		vertex_data = NULL;
		index_data = NULL;
		x_res = z_res = 0;
		return;
	}

	this->vertical_scaling = vertical_scaling;
	x_res = heightmap->w;
	z_res = heightmap->h;
	// Assume 8-bit data
	unsigned char *data = (unsigned char*)heightmap->pixels;

	allocCount(x_res * z_res, (x_res - 1) * (z_res - 1) * 2);

	// Load vertex coordinates and uv data
	for (int z = 0; z < z_res; z++)
		for (int x = 0; x < x_res; x++) {
			// Vertex coords
			unsigned int index_low = vindex(x, z);
			vertex_data[index_low] = (GLfloat)x - ((GLfloat)x_res / 2.0f);
			vertex_data[index_low+1] = (GLfloat)(data[z * x_res + x]) * vertical_scaling / 256.0f;
			vertex_data[index_low+2] = (GLfloat)z - ((GLfloat)z_res / 2.0f);

			// Vertex UV
			unsigned int uv_index_low = 2 * (z * x_res + x);
			uv_data[uv_index_low] = z % 2 ? 0.0f : 1.0f;
			uv_data[uv_index_low+1] = x % 2 ? 0.0f : 1.0f;
		}

	// Generate triangle indices
	for (int z = 0; z < (z_res - 1); z++)
		for (int x = 0; x < (x_res - 1); x++) {
			unsigned int index_low = 6 * (z * (x_res - 1) + x);

			index_data[index_low+0] = z * x_res + x + 1;
			index_data[index_low+1] = z * x_res + x;
			index_data[index_low+2] = (z+1) * x_res + x + 1;

			index_data[index_low+3] = z * x_res + x;
			index_data[index_low+4] = (z+1) * x_res + x;
			index_data[index_low+5] = (z+1) * x_res + x + 1;
		}

	// Compute normals
	for (int z = 1; z < (z_res - 1); z++)
		for (int x = 1; x < (x_res - 1); x++) {
			// coordinates of neighbour vertices
			glm::vec3 mid(vecx(x,z), vecy(x,z), vecz(x,z)),
				west(vecx(x-1,z), vecy(x-1,z), vecz(x-1,z)),
				north(vecx(x,z+1), vecy(x,z+1), vecz(x,z+1)),
				east(vecx(x+1,z), vecy(x+1,z), vecz(x+1,z)),
				south(vecx(x,z-1), vecy(x,z-1), vecz(x,z-1));

			// average face normals for a smooth vertex normal
			glm::vec3 triangle_normal_acc;
			triangle_normal_acc = glm::fastNormalize(glm::cross(mid - north, west - north));
			triangle_normal_acc += glm::fastNormalize(glm::cross(mid - east, north - east));
			triangle_normal_acc += glm::fastNormalize(glm::cross(mid - south, east - south));
			triangle_normal_acc += glm::fastNormalize(glm::cross(mid - west, south - west));
			triangle_normal_acc *= 0.25f;

			memcpy(&normal_data[vindex(x,z)], (float*)glm::value_ptr(triangle_normal_acc), sizeof(float)*3);
		}

	syncBuffers();
	SDL_FreeSurface(heightmap);

	Material *m = new Material();
	m->ambient = glm::vec4(0.5f, 0.5f, 0.5f, 1.0f);
	//m->ambient = glm::vec4(0,0,0,1);
	m->diffuse = glm::vec4(1.0f);
	m->texture = new Texture("textures/ground.bmp");
	setMaterial(m);
}

Terrain::~Terrain()
{
	delete vertex_data;
	delete uv_data;
	delete normal_data;
	delete index_data;
}

/// Returns interpolated height for the given (x,z) coordinates.
// The coordinates are in object space, (0,0) beeing the center.
GLfloat Terrain::getHeight(GLfloat x, GLfloat z)
{
	int ix = (int)floor(x) + x_res / 2;
	int iz = (int)floor(z) + z_res / 2;

	// check boundaries
	if (
			(ix < 0) ||
			((ix+1) >= x_res) ||
			(iz < 0) ||
			((iz+1) >= z_res))
		return 0.0f;

	float dx = x - floor(x);
	float dz = z - floor(z);

	// bilinear interpolation of height values
	float h0 = (1.0f - dx) * vecy(ix,iz) + dx * vecy(ix+1, iz);
	float h1 = (1.0f - dx) * vecy(ix,iz+1) + dx * vecy(ix+1, iz+1);
	return (1.0f - dz) * h0 + dz * h1;
}

<|endoftext|>