<commit_before>#include "upload_riak.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#include <algorithm>

#include "duplex_curl.h"
#include "logging.h"

using namespace upload;

RiakPushWorker::Context* RiakPushWorker::GenerateContext(
                            SpoolerBackend<RiakPushWorker> *master,
                            const std::string              &upstream_urls) {
  // read configuration
  // TODO...

  std::vector<std::string> upstream_url_vector = SplitString(upstream_urls, ',');
  return new Context(master, upstream_url_vector);
}

int RiakPushWorker::GetNumberOfWorkers(const Context *context) {
  return context->upstream_urls.size();
}

const std::string& RiakPushWorker::Context::AcquireUpstreamUrl() const {
  assert (upstream_urls.size() > 0);
  // get an unique upstream URL and set the pointer to the next one...
  const std::string& result = upstream_urls[next_upstream_url_];
  next_upstream_url_ = (next_upstream_url_ + 1) % upstream_urls.size();
  return result;
}

RiakPushWorker::RiakPushWorker(Context* context) :
  context_(context),
  initialized_(false),
  http_headers_(NULL)
{
  LockGuard<Context> lock(context);
  upstream_url_ = context->AcquireUpstreamUrl();
}

RiakPushWorker::~RiakPushWorker() {
  curl_easy_cleanup(curl_);
  curl_slist_free_all(http_headers_);
  curl_global_cleanup();
}

bool RiakPushWorker::Initialize() {
  bool retval = AbstractPushWorker::Initialize();
  if (!retval)
    return false;

  // initialize libcurl
  int cretval = curl_global_init(CURL_GLOBAL_ALL);
  if (cretval != 0) {
    LogCvmfs(kLogSpooler, kLogStderr,
      "failed to initialize curl in riak spooler. Errorcode: %d", cretval);
    return false;
  }

  // initialize cURL handle
  curl_ = curl_easy_init();
  if (! curl_) {
    LogCvmfs(kLogSpooler, kLogStderr, "failed to initialize cURL handle.");
    return false;
  }

  // configure cURL handle
  LogCvmfs(kLogSpooler, kLogVerboseMsg, "Configuring cURL handle for putting "
                                        "files into a Riak instance");
  if (curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L)    != CURLE_OK) return false;
  if (curl_easy_setopt(curl_, CURLOPT_TCP_KEEPALIVE, 1L) != CURLE_OK) return false;
  if (curl_easy_setopt(curl_, CURLOPT_UPLOAD, 1L)        != CURLE_OK) return false;

  http_headers_ = curl_slist_append(http_headers_, "Content-Type: application/octet-stream");
  if (curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, http_headers_) != CURLE_OK) return false;

  // all done
  LogCvmfs(kLogSpooler, kLogVerboseMsg, "successfully initialized Riak "
                                        "spooler backend");

  initialized_ = true;
  return true;
}

void RiakPushWorker::ProcessCopyJob(StorageCopyJob *copy_job) {
  if (copy_job->move()) {
    LogCvmfs(kLogSpooler, kLogStderr, "RiakPushWorker does not support "
                                      "move at the moment.");
    copy_job->Failed();
    return;
  }

  const int retval = PushFileToRiak(GenerateRiakKey(copy_job->remote_path()),
                                    copy_job->local_path());

  copy_job->Finished(retval);
}

void RiakPushWorker::ProcessCompressionJob(
                                      StorageCompressionJob *compression_job) {
  if (compression_job->move()) {
    LogCvmfs(kLogSpooler, kLogStderr, "RiakPushWorker does not support "
                                      "move at the moment.");
    compression_job->Failed();
    return;
  }

  const std::string &local_path   = compression_job->local_path();
        hash::Any   &content_hash = compression_job->content_hash();

  // compress the file to a temporary location
  static const std::string tmp_dir = "/tmp";
  std::string tmp_file_path;
  hash::Any compressed_hash(hash::kSha1);
  if (! CompressToTempFile(local_path,
                           tmp_dir,
                           &tmp_file_path,
                           &content_hash) ) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to compress file before pushing "
                                      "to Riak: %s",
             local_path.c_str());

    compression_job->Failed(101);
    return;
  }

  // push to Riak
  const int retval = PushFileToRiak(GenerateRiakKey(compression_job),
                                     tmp_file_path);

  // clean up and go home
  compression_job->Finished(retval);
  unlink(tmp_file_path.c_str());
}

bool RiakPushWorker::CompressToTempFile(const std::string &source_file_path,
                                        const std::string &destination_dir,
                                        std::string       *tmp_file_path,
                                        hash::Any         *content_hash) const {
  // Create a temporary file at the given destination directory
  FILE *fcas = CreateTempFile(destination_dir + "/cvmfs", 0777, "w",
                              tmp_file_path);
  if (fcas == NULL) {
    LogCvmfs(kLogSpooler, kLogStderr, "failed to create temporary file %s",
             tmp_file_path->c_str());
    return false;
  }

  // Compress the provided source file and write the result into the temporary.
  // Additionally computes the content hash of the compressed data
  int retval = zlib::CompressPath2File(source_file_path, fcas, content_hash);
  if (! retval) {
    LogCvmfs(kLogSpooler, kLogStderr, "failed to compress file %s to temporary "
                                      "file %s",
             source_file_path.c_str(), tmp_file_path->c_str());

    unlink(tmp_file_path->c_str());
    return false;
  }
  fclose(fcas);

  return true;
}

std::string RiakPushWorker::GenerateRiakKey(
                          const StorageCompressionJob *compression_job) const {
  assert (!compression_job->content_hash().IsNull());

  return compression_job->remote_dir()              +
         compression_job->content_hash().ToString() +
         compression_job->file_suffix();
}

std::string RiakPushWorker::GenerateRiakKey(const std::string &remote_path) const {
  // removes slashes (/) from the remote_path
  std::string result;
  std::remove_copy(remote_path.begin(),
                   remote_path.end(),
                   std::back_inserter(result),
                   '/');
  return result;
}

int RiakPushWorker::PushFileToRiak(const std::string &key,
                                   const std::string &file_path) {
  LogCvmfs(kLogSpooler, kLogVerboseMsg, "pushing file %s to Riak using key %s",
           file_path.c_str(), key.c_str());

  const std::string url = CreateRequestUrl(key);
  FILE *hd_src;

  CURLcode res;
  int      retcode = -1;

  // find the size of the file to be uploaded
  struct stat file_info;
  int hd = open(file_path.c_str(), O_RDONLY);
  if (hd < 0) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to stat file %s",
             file_path.c_str());
    retcode = 1;
    close(hd);
    goto out;
  }
  fstat(hd, &file_info);
  close(hd);

  // open the file for reading
  hd_src = fopen(file_path.c_str(), "rb");
  if (hd_src == NULL) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to open file %s for reading.",
             file_path.c_str());
    retcode = 2;
    goto out;
  }

  // set url for Riak put command
  if (curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()) != CURLE_OK) {
    retcode = 3;
    goto out;
  }

  // set file size of the file to be uploaded
  if (curl_easy_setopt(curl_, CURLOPT_INFILESIZE_LARGE,
                       (curl_off_t)file_info.st_size) != CURLE_OK) {
    retcode = 4;
    goto out;
  }

  // specify the file handle to be uploaded
  if (curl_easy_setopt(curl_, CURLOPT_READDATA, hd_src) != CURLE_OK) {
    retcode = 5;
    goto out;
  }

  // do the actual business
  res = curl_easy_perform(curl_);
  if(res != CURLE_OK) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to upload file %s to Riak "
                                      "because: '%s'",
             file_path.c_str(), curl_easy_strerror(res));
    retcode = 6;
    goto out;
  }

  // all went well...
  retcode = 0;

out:
  // close the uploaded file
  fclose(hd_src);
  return retcode;
}

std::string RiakPushWorker::CreateRequestUrl(const std::string &key) const {
  return upstream_url_ + "/" + key;
}

bool RiakPushWorker::IsReady() const {
  const bool ready = AbstractPushWorker::IsReady();
  return ready && initialized_;
}
<commit_msg>hardcoded ramdisk location<commit_after>#include "upload_riak.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#include <algorithm>

#include "duplex_curl.h"
#include "logging.h"

using namespace upload;

RiakPushWorker::Context* RiakPushWorker::GenerateContext(
                            SpoolerBackend<RiakPushWorker> *master,
                            const std::string              &upstream_urls) {
  // read configuration
  // TODO...

  std::vector<std::string> upstream_url_vector = SplitString(upstream_urls, ',');
  return new Context(master, upstream_url_vector);
}

int RiakPushWorker::GetNumberOfWorkers(const Context *context) {
  return context->upstream_urls.size() * GetNumberOfCpuCores();
}

const std::string& RiakPushWorker::Context::AcquireUpstreamUrl() const {
  assert (upstream_urls.size() > 0);
  // get an unique upstream URL and set the pointer to the next one...
  const std::string& result = upstream_urls[next_upstream_url_];
  next_upstream_url_ = (next_upstream_url_ + 1) % upstream_urls.size();
  return result;
}

RiakPushWorker::RiakPushWorker(Context* context) :
  context_(context),
  initialized_(false),
  http_headers_(NULL)
{
  LockGuard<Context> lock(context);
  upstream_url_ = context->AcquireUpstreamUrl();
}

RiakPushWorker::~RiakPushWorker() {
  curl_easy_cleanup(curl_);
  curl_slist_free_all(http_headers_);
  curl_global_cleanup();
}

bool RiakPushWorker::Initialize() {
  bool retval = AbstractPushWorker::Initialize();
  if (!retval)
    return false;

  // initialize libcurl
  int cretval = curl_global_init(CURL_GLOBAL_ALL);
  if (cretval != 0) {
    LogCvmfs(kLogSpooler, kLogStderr,
      "failed to initialize curl in riak spooler. Errorcode: %d", cretval);
    return false;
  }

  // initialize cURL handle
  curl_ = curl_easy_init();
  if (! curl_) {
    LogCvmfs(kLogSpooler, kLogStderr, "failed to initialize cURL handle.");
    return false;
  }

  // configure cURL handle
  LogCvmfs(kLogSpooler, kLogVerboseMsg, "Configuring cURL handle for putting "
                                        "files into a Riak instance");
  if (curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L)    != CURLE_OK) return false;
  if (curl_easy_setopt(curl_, CURLOPT_TCP_KEEPALIVE, 1L) != CURLE_OK) return false;
  if (curl_easy_setopt(curl_, CURLOPT_UPLOAD, 1L)        != CURLE_OK) return false;

  http_headers_ = curl_slist_append(http_headers_, "Content-Type: application/octet-stream");
  if (curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, http_headers_) != CURLE_OK) return false;

  // all done
  LogCvmfs(kLogSpooler, kLogVerboseMsg, "successfully initialized Riak "
                                        "spooler backend");

  initialized_ = true;
  return true;
}

void RiakPushWorker::ProcessCopyJob(StorageCopyJob *copy_job) {
  if (copy_job->move()) {
    LogCvmfs(kLogSpooler, kLogStderr, "RiakPushWorker does not support "
                                      "move at the moment.");
    copy_job->Failed();
    return;
  }

  const int retval = PushFileToRiak(GenerateRiakKey(copy_job->remote_path()),
                                    copy_job->local_path());

  copy_job->Finished(retval);
}

void RiakPushWorker::ProcessCompressionJob(
                                      StorageCompressionJob *compression_job) {
  if (compression_job->move()) {
    LogCvmfs(kLogSpooler, kLogStderr, "RiakPushWorker does not support "
                                      "move at the moment.");
    compression_job->Failed();
    return;
  }

  const std::string &local_path   = compression_job->local_path();
        hash::Any   &content_hash = compression_job->content_hash();

  // compress the file to a temporary location
  static const std::string tmp_dir = "/ramdisk";
  std::string tmp_file_path;
  hash::Any compressed_hash(hash::kSha1);
  if (! CompressToTempFile(local_path,
                           tmp_dir,
                           &tmp_file_path,
                           &content_hash) ) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to compress file before pushing "
                                      "to Riak: %s",
             local_path.c_str());

    compression_job->Failed(101);
    return;
  }

  // push to Riak
  const int retval = PushFileToRiak(GenerateRiakKey(compression_job),
                                     tmp_file_path);

  // clean up and go home
  compression_job->Finished(retval);
  unlink(tmp_file_path.c_str());
}

bool RiakPushWorker::CompressToTempFile(const std::string &source_file_path,
                                        const std::string &destination_dir,
                                        std::string       *tmp_file_path,
                                        hash::Any         *content_hash) const {
  // Create a temporary file at the given destination directory
  FILE *fcas = CreateTempFile(destination_dir + "/cvmfs", 0777, "w",
                              tmp_file_path);
  if (fcas == NULL) {
    LogCvmfs(kLogSpooler, kLogStderr, "failed to create temporary file %s",
             tmp_file_path->c_str());
    return false;
  }

  // Compress the provided source file and write the result into the temporary.
  // Additionally computes the content hash of the compressed data
  int retval = zlib::CompressPath2File(source_file_path, fcas, content_hash);
  if (! retval) {
    LogCvmfs(kLogSpooler, kLogStderr, "failed to compress file %s to temporary "
                                      "file %s",
             source_file_path.c_str(), tmp_file_path->c_str());

    unlink(tmp_file_path->c_str());
    return false;
  }
  fclose(fcas);

  return true;
}

std::string RiakPushWorker::GenerateRiakKey(
                          const StorageCompressionJob *compression_job) const {
  assert (!compression_job->content_hash().IsNull());

  return compression_job->remote_dir()              +
         compression_job->content_hash().ToString() +
         compression_job->file_suffix();
}

std::string RiakPushWorker::GenerateRiakKey(const std::string &remote_path) const {
  // removes slashes (/) from the remote_path
  std::string result;
  std::remove_copy(remote_path.begin(),
                   remote_path.end(),
                   std::back_inserter(result),
                   '/');
  return result;
}

int RiakPushWorker::PushFileToRiak(const std::string &key,
                                   const std::string &file_path) {
  LogCvmfs(kLogSpooler, kLogVerboseMsg, "pushing file %s to Riak using key %s",
           file_path.c_str(), key.c_str());

  const std::string url = CreateRequestUrl(key);
  FILE *hd_src;

  CURLcode res;
  int      retcode = -1;

  // find the size of the file to be uploaded
  struct stat file_info;
  int hd = open(file_path.c_str(), O_RDONLY);
  if (hd < 0) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to stat file %s",
             file_path.c_str());
    retcode = 1;
    close(hd);
    goto out;
  }
  fstat(hd, &file_info);
  close(hd);

  // open the file for reading
  hd_src = fopen(file_path.c_str(), "rb");
  if (hd_src == NULL) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to open file %s for reading.",
             file_path.c_str());
    retcode = 2;
    goto out;
  }

  // set url for Riak put command
  if (curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()) != CURLE_OK) {
    retcode = 3;
    goto out;
  }

  // set file size of the file to be uploaded
  if (curl_easy_setopt(curl_, CURLOPT_INFILESIZE_LARGE,
                       (curl_off_t)file_info.st_size) != CURLE_OK) {
    retcode = 4;
    goto out;
  }

  // specify the file handle to be uploaded
  if (curl_easy_setopt(curl_, CURLOPT_READDATA, hd_src) != CURLE_OK) {
    retcode = 5;
    goto out;
  }

  // do the actual business
  res = curl_easy_perform(curl_);
  if(res != CURLE_OK) {
    LogCvmfs(kLogSpooler, kLogStderr, "Failed to upload file %s to Riak "
                                      "because: '%s'",
             file_path.c_str(), curl_easy_strerror(res));
    retcode = 6;
    goto out;
  }

  // all went well...
  retcode = 0;

out:
  // close the uploaded file
  fclose(hd_src);
  return retcode;
}

std::string RiakPushWorker::CreateRequestUrl(const std::string &key) const {
  return upstream_url_ + "/" + key;
}

bool RiakPushWorker::IsReady() const {
  const bool ready = AbstractPushWorker::IsReady();
  return ready && initialized_;
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <Containers/Array.h>
#include <TestSuite/Tester.h>
#include <Utility/Directory.h>

#include "Text/AbstractFont.h"

#include "testConfigure.h"

namespace Magnum { namespace Text { namespace Test {

class AbstractFontTest: public TestSuite::Tester {
    public:
        explicit AbstractFontTest();

        void openSingleData();
        void openFile();
};

AbstractFontTest::AbstractFontTest() {
    addTests({&AbstractFontTest::openSingleData,
              &AbstractFontTest::openFile});
}

namespace {

class SingleDataFont: public Text::AbstractFont {
    public:
        Features doFeatures() const override { return Feature::OpenData; }
        bool doIsOpened() const override { return opened; }
        void doClose() override {}

        void doOpenSingleData(const Containers::ArrayReference<const unsigned char> data, Float) override {
            opened = (data.size() == 1 && data[0] == 0xa5);
        }

        UnsignedInt doGlyphId(char32_t) override { return 0; }

        Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }

        AbstractLayouter* doLayout(const GlyphCache*, Float, const std::string&) {
            return nullptr;
        }

        bool opened = false;
};

}

void AbstractFontTest::openSingleData() {
    /* doOpenData() should call doOpenSingleData() */
    SingleDataFont font;
    const unsigned char data[] = {0xa5};
    CORRADE_VERIFY(!font.isOpened());
    font.openData({{{}, data}}, 3.0f);
    CORRADE_VERIFY(font.isOpened());
}

void AbstractFontTest::openFile() {
    /* doOpenFile() should call doOpenSingleData() */
    SingleDataFont font;
    CORRADE_VERIFY(!font.isOpened());
    font.openFile(Utility::Directory::join(TEXT_TEST_DIR, "data.bin"), 3.0f);
    CORRADE_VERIFY(font.isOpened());
}

}}}

CORRADE_TEST_MAIN(Magnum::Text::Test::AbstractFontTest)
<commit_msg>GCC 4.6 compatibility: no in-class data initializers.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <Containers/Array.h>
#include <TestSuite/Tester.h>
#include <Utility/Directory.h>

#include "Text/AbstractFont.h"

#include "testConfigure.h"

namespace Magnum { namespace Text { namespace Test {

class AbstractFontTest: public TestSuite::Tester {
    public:
        explicit AbstractFontTest();

        void openSingleData();
        void openFile();
};

AbstractFontTest::AbstractFontTest() {
    addTests({&AbstractFontTest::openSingleData,
              &AbstractFontTest::openFile});
}

namespace {

class SingleDataFont: public Text::AbstractFont {
    public:
        explicit SingleDataFont(): opened(false) {}

        Features doFeatures() const override { return Feature::OpenData; }
        bool doIsOpened() const override { return opened; }
        void doClose() override {}

        void doOpenSingleData(const Containers::ArrayReference<const unsigned char> data, Float) override {
            opened = (data.size() == 1 && data[0] == 0xa5);
        }

        UnsignedInt doGlyphId(char32_t) override { return 0; }

        Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }

        AbstractLayouter* doLayout(const GlyphCache*, Float, const std::string&) {
            return nullptr;
        }

        bool opened;
};

}

void AbstractFontTest::openSingleData() {
    /* doOpenData() should call doOpenSingleData() */
    SingleDataFont font;
    const unsigned char data[] = {0xa5};
    CORRADE_VERIFY(!font.isOpened());
    font.openData({{{}, data}}, 3.0f);
    CORRADE_VERIFY(font.isOpened());
}

void AbstractFontTest::openFile() {
    /* doOpenFile() should call doOpenSingleData() */
    SingleDataFont font;
    CORRADE_VERIFY(!font.isOpened());
    font.openFile(Utility::Directory::join(TEXT_TEST_DIR, "data.bin"), 3.0f);
    CORRADE_VERIFY(font.isOpened());
}

}}}

CORRADE_TEST_MAIN(Magnum::Text::Test::AbstractFontTest)
<|endoftext|>


<commit_before>#include <QtCore>
#include "nicolive.h"
#include "nico-live.hpp"
#include "nico-live-watcher.hpp"
#include "nicolive-ui.h"

NicoLiveWatcher::NicoLiveWatcher(NicoLive *nicolive, int margin_sec) :
	QObject(nicolive),
	nicolive(nicolive),
	marginTime(margin_sec * 1000)
{
	this->timer = new QTimer(this);
	this->timer->setSingleShot(true);
	connect(timer, SIGNAL(timeout()), this, SLOT(watch()));
}

NicoLiveWatcher::~NicoLiveWatcher()
{
	if (isActive())
		stop();
}

void NicoLiveWatcher::start(long long sec)
{
	if (sec < NicoLiveWatcher::MIN_INTERVAL / 1000)
		sec = NicoLiveWatcher::MIN_INTERVAL / 1000;
	else if (sec > NicoLiveWatcher::MAX_INTERVAL / 1000)
		sec = NicoLiveWatcher::MAX_INTERVAL / 1000;

	this->interval = static_cast<int>(sec * 1000);
	if (this->interval < NicoLiveWatcher::MIN_INTERVAL)
		this->interval = NicoLiveWatcher::MIN_INTERVAL;
	if (!this->timer->isActive()) {
		nicolive_log_debug("check session before timer start");
		nicolive->checkSession();
		nicolive_log_debug("start watch, interval: %lld",
				this->interval);
		// this->timer->start(this->interval);
		this->timer->start(this->marginTime);
	}
	this->active = true;
}

void NicoLiveWatcher::stop()
{
	if (this->timer->isActive()) {
		nicolive_log_debug("stop watch ");
		this->timer->stop();
	}
	this->active = false;
}

bool NicoLiveWatcher::isActive()
{
	return this->active;
}

int NicoLiveWatcher::remainingTime()
{
	return this->timer->remainingTime() / 1000;
}

void NicoLiveWatcher::watch()
{
	nicolive_log_debug("watching!");

	int next_interval = this->interval;
	int remaining_msec;

	nicolive->sitePubStat();
	remaining_msec = nicolive->getRemainingLive() * 1000;
	if (remaining_msec < 0)
		remaining_msec = 0;

	if (nicolive->getLiveId().isEmpty()) {
		if (nicolive->isOnair()) {
			nicolive_log_debug("stop streaming because live end");
			nicolive_streaming_click();
			next_interval = this->marginTime;
		}
	} else {
		if (nicolive->getLiveId() != nicolive->getOnairLiveId()) {
			if (nicolive->isOnair()) {
				nicolive_log_debug(
					"stop streaming for restart");
				nicolive_streaming_click();
				QThread::sleep(1); // sleep 1 sec
			}
			nicolive_log_debug("start streaming for next live");
			nicolive_streaming_click();
		} else if (remaining_msec + this->marginTime < next_interval) {
			next_interval = remaining_msec + this->marginTime;
		}
	}
	this->timer->start(next_interval);
}
<commit_msg>最小秒数のチェックが二重になってた。<commit_after>#include <QtCore>
#include "nicolive.h"
#include "nico-live.hpp"
#include "nico-live-watcher.hpp"
#include "nicolive-ui.h"

NicoLiveWatcher::NicoLiveWatcher(NicoLive *nicolive, int margin_sec) :
	QObject(nicolive),
	nicolive(nicolive),
	marginTime(margin_sec * 1000)
{
	this->timer = new QTimer(this);
	this->timer->setSingleShot(true);
	connect(timer, SIGNAL(timeout()), this, SLOT(watch()));
}

NicoLiveWatcher::~NicoLiveWatcher()
{
	if (isActive())
		stop();
}

void NicoLiveWatcher::start(long long sec)
{
	if (sec < NicoLiveWatcher::MIN_INTERVAL / 1000)
		sec = NicoLiveWatcher::MIN_INTERVAL / 1000;
	else if (sec > NicoLiveWatcher::MAX_INTERVAL / 1000)
		sec = NicoLiveWatcher::MAX_INTERVAL / 1000;
	this->interval = static_cast<int>(sec * 1000);

	if (!this->timer->isActive()) {
		nicolive_log_debug("check session before timer start");
		nicolive->checkSession();
		nicolive_log_debug("start watch, interval: %lld",
				this->interval);
		// this->timer->start(this->interval);
		this->timer->start(this->marginTime);
	}
	this->active = true;
}

void NicoLiveWatcher::stop()
{
	if (this->timer->isActive()) {
		nicolive_log_debug("stop watch ");
		this->timer->stop();
	}
	this->active = false;
}

bool NicoLiveWatcher::isActive()
{
	return this->active;
}

int NicoLiveWatcher::remainingTime()
{
	return this->timer->remainingTime() / 1000;
}

void NicoLiveWatcher::watch()
{
	nicolive_log_debug("watching!");

	int next_interval = this->interval;
	int remaining_msec;

	nicolive->sitePubStat();
	remaining_msec = nicolive->getRemainingLive() * 1000;
	if (remaining_msec < 0)
		remaining_msec = 0;

	if (nicolive->getLiveId().isEmpty()) {
		if (nicolive->isOnair()) {
			nicolive_log_debug("stop streaming because live end");
			nicolive_streaming_click();
			next_interval = this->marginTime;
		}
	} else {
		if (nicolive->getLiveId() != nicolive->getOnairLiveId()) {
			if (nicolive->isOnair()) {
				nicolive_log_debug(
					"stop streaming for restart");
				nicolive_streaming_click();
				QThread::sleep(1); // sleep 1 sec
			}
			nicolive_log_debug("start streaming for next live");
			nicolive_streaming_click();
		} else if (remaining_msec + this->marginTime < next_interval) {
			next_interval = remaining_msec + this->marginTime;
		}
	}
	this->timer->start(next_interval);
}
<|endoftext|>


<commit_before>#ifdef _WIN32
#define hypot _hypot
#endif

#include "opencv/cv.h"
#include "opencv2/highgui/highgui.hpp"
#include "math.h"
#include <limits>
#ifdef _CHAR16T
#define CHAR16_T
#endif
#include <Python.h>
#include <numpy/arrayobject.h>

#include "mtf/Utilities/miscUtils.h"

static const int MAX_COUNT = 500;
static const int MAX_IMG = 2;
static int win_size = 4;
static CvPoint2D32f* points[3] = { 0,0,0 };

static PyArrayObject *img_py_1, *img_py_2;
static PyArrayObject *pts_py_1, *pts_py_2;
static int Level;

static PyObject* get(PyObject* self, PyObject* args);

static PyMethodDef pyLKMethods[] = {
	{ "get", get, METH_VARARGS },
	{ NULL, NULL }     /* Sentinel - marks the end of this structure */
};

PyMODINIT_FUNC initpyLK() {
	(void)Py_InitModule("pyLK", pyLKMethods);
	import_array();  // Must be present for NumPy.  Called first after above line.
}

static void euclideanDistance(CvPoint2D32f *point1, CvPoint2D32f *point2, float *match, int nPts) {

	for(int i = 0; i < nPts; i++) {

		match[i] = sqrt((point1[i].x - point2[i].x)*(point1[i].x - point2[i].x) +
			(point1[i].y - point2[i].y)*(point1[i].y - point2[i].y));

	}
}

static void normCrossCorrelation(IplImage *imgI, IplImage *imgJ, CvPoint2D32f *points0, CvPoint2D32f *points1,
	int nPts, char *status, float *match, int winsize, int method) {

	IplImage *rec0 = cvCreateImage(cvSize(winsize, winsize), 8, 1);
	IplImage *rec1 = cvCreateImage(cvSize(winsize, winsize), 8, 1);
	IplImage *res = cvCreateImage(cvSize(1, 1), IPL_DEPTH_32F, 1);

	for(int i = 0; i < nPts; i++) {
		if(status[i] == 1) {
			cvGetRectSubPix(imgI, rec0, points0[i]);
			cvGetRectSubPix(imgJ, rec1, points1[i]);
			cvMatchTemplate(rec0, rec1, res, method);
			match[i] = ((float *)(res->imageData))[0];

		} else {
			match[i] = 0.0;
		}
	}
	cvReleaseImage(&rec0);
	cvReleaseImage(&rec1);
	cvReleaseImage(&res);

}

static PyObject* get(PyObject* self, PyObject* args) {

	PySys_WriteStdout("\nStarting pyLK\n");

	/*parse first input array*/
	if(!PyArg_ParseTuple(args, "O!O!O!O!|i",
		&PyArray_Type, &img_py_1,
		&PyArray_Type, &img_py_2,
		&PyArray_Type, &pts_py_1,
		&PyArray_Type, &pts_py_2, &Level)) {
		PyErr_SetString(PyExc_IOError, "Input arguments could not be parsed");
		PyErr_PrintEx(1);
	}
	if(img_py_1 == NULL || img_py_2 == NULL) {
		PyErr_SetString(PyExc_IOError, "img_py_1 or img_py_2 is NULL");
		PyErr_PrintEx(1);
	}
	if(pts_py_1 == NULL || pts_py_2 == NULL) {
		PyErr_SetString(PyExc_IOError, "pts_py_1 or pts_py_2 is NULL");
		PyErr_PrintEx(1);
	}
	if(img_py_1->nd != 2 || img_py_2->nd != 2) {
		PyErr_SetString(PyExc_IOError, "Both input images must be 2 dimensional arrays");
		PyErr_PrintEx(1);
	}
	if(pts_py_1->nd != 2 || pts_py_2->nd != 2) {
		PyErr_SetString(PyExc_IOError, "Both point sets must be 2 dimensional arrays");
		PyErr_PrintEx(1);
	}

	int img_height = img_py_1->dimensions[0];
	int img_width = img_py_1->dimensions[1];
	if(img_height != img_py_2->dimensions[0] || img_width != img_py_2->dimensions[1]) {
		PyErr_SetString(PyExc_IOError, "Input images have inconsistent dimensions");
		PyErr_PrintEx(1);
	}
	if(pts_py_1->dimensions[1] != 2 || pts_py_2->dimensions[1] != 2) {
		PyErr_SetString(PyExc_IOError, "Both point sets must have 2 columns");
		PyErr_PrintEx(1);
	}
	int nPts = pts_py_1->dimensions[0];
	if(nPts != pts_py_2->dimensions[0]) {
		PyErr_SetString(PyExc_IOError, "Both point sets must have the same number of points");
		PyErr_PrintEx(1);
	}
	PySys_WriteStdout("img_height: %d\t img_width: %d\n", img_height, img_width);
	PySys_WriteStdout("nPts: %d\n", nPts);
	PySys_WriteStdout("Level: %d\n", Level);

	//int dummy_input;
	//scanf("Press any key to continue: %d", &dummy_input);

	IplImage **IMG = (IplImage**)calloc(MAX_IMG, sizeof(IplImage*));
	IplImage **PYR = (IplImage**)calloc(MAX_IMG, sizeof(IplImage*));

	int I = 0;
	int J = 1;
	int Winsize = 10;

	// Images
	cv::Mat img_1(img_height, img_width, CV_8UC1, img_py_1->data);
	cv::Mat img_2(img_height, img_width, CV_8UC1, img_py_2->data);

	CvSize imageSize = cvSize(img_width, img_height);
	IMG[I] = new IplImage(img_1);
	PYR[I] = cvCreateImage(imageSize, 8, 1);
	IMG[J] = new IplImage(img_2);
	PYR[J] = cvCreateImage(imageSize, 8, 1);

	// Points
	cv::Mat ptsI = cv::Mat(nPts, 2, CV_32FC1, pts_py_1->data);
	cv::Mat ptsJ = cv::Mat(nPts, 2, CV_32FC1, pts_py_2->data);

	points[0] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // template
	points[1] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // target
	points[2] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // forward-backward

	for(int i = 0; i < nPts; i++) {
		points[0][i].x = ptsI.at<float>(i, 0); points[0][i].y = ptsI.at<float>(i, 1);
		points[1][i].x = ptsJ.at<float>(i, 0); points[1][i].y = ptsJ.at<float>(i, 1);
		points[2][i].x = ptsI.at<float>(i, 0); points[2][i].y = ptsI.at<float>(i, 1);
	}
	float *fb = (float*)cvAlloc(nPts*sizeof(float));
	char  *status = (char*)cvAlloc(nPts);
	cvCalcOpticalFlowPyrLK(IMG[I], IMG[J], PYR[I], PYR[J], points[0],
		points[1], nPts, cvSize(win_size, win_size), Level, status, 0,
		cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03), CV_LKFLOW_INITIAL_GUESSES);
	PySys_WriteStdout("Completed forward flow\n");
	cvCalcOpticalFlowPyrLK(IMG[J], IMG[I], PYR[J], PYR[I], points[1],
		points[2], nPts, cvSize(win_size, win_size), Level, status, 0,
		cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03),
		CV_LKFLOW_INITIAL_GUESSES | CV_LKFLOW_PYR_A_READY | CV_LKFLOW_PYR_B_READY);
	PySys_WriteStdout("Completed backward flow\n");

	float *ncc = (float*)cvAlloc(nPts*sizeof(float));
	normCrossCorrelation(IMG[I], IMG[J], points[0], points[1], nPts, status, ncc, Winsize, CV_TM_CCOEFF_NORMED);
	PySys_WriteStdout("Completed NCC computation \n");

	//float *ssd = (float*)cvAlloc(nPts*sizeof(float));
	//normCrossCorrelation(IMG[I],IMG[J],points[0],points[1],nPts, status, ssd, Winsize,CV_TM_SQDIFF);

	euclideanDistance(points[0], points[2], fb, nPts);
	PySys_WriteStdout("Completed Euclidean distance computation\n");

	// Output
	int dims[] = { 4, nPts };
	PyArrayObject *output_py = (PyArrayObject *)PyArray_FromDims(2, dims, NPY_FLOAT);
	cv::Mat output = cv::Mat(4, nPts, CV_32FC1, output_py->data);
	float nan = std::numeric_limits<float>::quiet_NaN();
	float inf = std::numeric_limits<float>::infinity();
	for(int i = 0; i < nPts; i++) {
		if(status[i] == 1) {
			output.at<float>(0, i) = points[1][i].x;
			output.at<float>(1, i) = points[1][i].y;
			output.at<float>(2, i) = fb[i];
			output.at<float>(3, i) = ncc[i];
		} else {
			output.at<float>(0, i) = nan;
			output.at<float>(1, i) = nan;
			output.at<float>(2, i) = nan;
			output.at<float>(3, i) = nan;
		}
	}
	PySys_WriteStdout("Completed writing to output matrix\n");

	mtf::utils::drawPts<float>(img_1, ptsI, cv::Scalar(0, 0, 0), 2);
	mtf::utils::drawPts<float>(img_2, ptsJ, cv::Scalar(0, 0, 0), 2);
	std::vector<cv::Mat> img_list;
	img_list.push_back(img_1);
	img_list.push_back(img_2);
	cv::Mat stacked_img = mtf::utils::stackImages(img_list);
	cv::imshow("Input Images", stacked_img);
	if(cv::waitKey(0) == 27) {
		Py_Exit(0);
	}
	mtf::utils::printMatrixToFile<float>(ptsI, nullptr, "ptsI.txt", "%.4f");
	mtf::utils::printMatrixToFile<float>(ptsJ, nullptr, "ptsJ.txt", "%.4f");

	// clean up
	for(int i = 0; i < MAX_IMG; i++) {
		//! sharing memory with Python array
		//cvReleaseImage(&(IMG[i]));
		cvReleaseImage(&(PYR[i]));
	}
	free(IMG);
	free(PYR);
	PySys_WriteStdout("Completed cleaning up\n");
	return Py_BuildValue("O", output_py);
}
<commit_msg>Fixes to pyLK to make its output format coincide with that used in LKCV;<commit_after>#ifdef _WIN32
#define hypot _hypot
#endif

#include "opencv/cv.h"
#include "opencv2/highgui/highgui.hpp"
#include "math.h"
#include <limits>
#ifdef _CHAR16T
#define CHAR16_T
#endif
#include <Python.h>
#include <numpy/arrayobject.h>

#include "mtf/Utilities/miscUtils.h"

static const int MAX_COUNT = 500;
static const int MAX_IMG = 2;
static int win_size = 4;
static CvPoint2D32f* points[3] = { 0,0,0 };

static PyArrayObject *img_py_1, *img_py_2;
static PyArrayObject *pts_py_1, *pts_py_2;
static int Level;

static PyObject* get(PyObject* self, PyObject* args);

static PyMethodDef pyLKMethods[] = {
	{ "get", get, METH_VARARGS },
	{ NULL, NULL }     /* Sentinel - marks the end of this structure */
};

PyMODINIT_FUNC initpyLK() {
	(void)Py_InitModule("pyLK", pyLKMethods);
	import_array();  // Must be present for NumPy.  Called first after above line.
}

static void euclideanDistance(CvPoint2D32f *point1, CvPoint2D32f *point2, float *match, int nPts) {

	for(int i = 0; i < nPts; i++) {

		match[i] = sqrt((point1[i].x - point2[i].x)*(point1[i].x - point2[i].x) +
			(point1[i].y - point2[i].y)*(point1[i].y - point2[i].y));

	}
}

static void normCrossCorrelation(IplImage *imgI, IplImage *imgJ, CvPoint2D32f *points0, CvPoint2D32f *points1,
	int nPts, char *status, float *match, int winsize, int method) {

	IplImage *rec0 = cvCreateImage(cvSize(winsize, winsize), 8, 1);
	IplImage *rec1 = cvCreateImage(cvSize(winsize, winsize), 8, 1);
	IplImage *res = cvCreateImage(cvSize(1, 1), IPL_DEPTH_32F, 1);

	for(int i = 0; i < nPts; i++) {
		if(status[i] == 1) {
			cvGetRectSubPix(imgI, rec0, points0[i]);
			cvGetRectSubPix(imgJ, rec1, points1[i]);
			cvMatchTemplate(rec0, rec1, res, method);
			match[i] = ((float *)(res->imageData))[0];

		} else {
			match[i] = 0.0;
		}
	}
	cvReleaseImage(&rec0);
	cvReleaseImage(&rec1);
	cvReleaseImage(&res);

}

static PyObject* get(PyObject* self, PyObject* args) {

	PySys_WriteStdout("\nStarting pyLK\n");

	/*parse first input array*/
	if(!PyArg_ParseTuple(args, "O!O!O!O!|i",
		&PyArray_Type, &img_py_1,
		&PyArray_Type, &img_py_2,
		&PyArray_Type, &pts_py_1,
		&PyArray_Type, &pts_py_2, &Level)) {
		PyErr_SetString(PyExc_IOError, "Input arguments could not be parsed");
		PyErr_PrintEx(1);
	}
	if(img_py_1 == NULL || img_py_2 == NULL) {
		PyErr_SetString(PyExc_IOError, "img_py_1 or img_py_2 is NULL");
		PyErr_PrintEx(1);
	}
	if(pts_py_1 == NULL || pts_py_2 == NULL) {
		PyErr_SetString(PyExc_IOError, "pts_py_1 or pts_py_2 is NULL");
		PyErr_PrintEx(1);
	}
	if(img_py_1->nd != 2 || img_py_2->nd != 2) {
		PyErr_SetString(PyExc_IOError, "Both input images must be 2 dimensional arrays");
		PyErr_PrintEx(1);
	}
	if(pts_py_1->nd != 2 || pts_py_2->nd != 2) {
		PyErr_SetString(PyExc_IOError, "Both point sets must be 2 dimensional arrays");
		PyErr_PrintEx(1);
	}

	int img_height = img_py_1->dimensions[0];
	int img_width = img_py_1->dimensions[1];
	if(img_height != img_py_2->dimensions[0] || img_width != img_py_2->dimensions[1]) {
		PyErr_SetString(PyExc_IOError, "Input images have inconsistent dimensions");
		PyErr_PrintEx(1);
	}
	if(pts_py_1->dimensions[1] != 2 || pts_py_2->dimensions[1] != 2) {
		PyErr_SetString(PyExc_IOError, "Both point sets must have 2 columns");
		PyErr_PrintEx(1);
	}
	int nPts = pts_py_1->dimensions[0];
	if(nPts != pts_py_2->dimensions[0]) {
		PyErr_SetString(PyExc_IOError, "Both point sets must have the same number of points");
		PyErr_PrintEx(1);
	}
	PySys_WriteStdout("img_height: %d\t img_width: %d\n", img_height, img_width);
	PySys_WriteStdout("nPts: %d\n", nPts);
	PySys_WriteStdout("Level: %d\n", Level);

	//int dummy_input;
	//scanf("Press any key to continue: %d", &dummy_input);

	IplImage **IMG = (IplImage**)calloc(MAX_IMG, sizeof(IplImage*));
	IplImage **PYR = (IplImage**)calloc(MAX_IMG, sizeof(IplImage*));

	int I = 0;
	int J = 1;
	int Winsize = 10;

	// Images
	cv::Mat img_1(img_height, img_width, CV_8UC1, img_py_1->data);
	cv::Mat img_2(img_height, img_width, CV_8UC1, img_py_2->data);

	CvSize imageSize = cvSize(img_width, img_height);
	IMG[I] = new IplImage(img_1);
	PYR[I] = cvCreateImage(imageSize, 8, 1);
	IMG[J] = new IplImage(img_2);
	PYR[J] = cvCreateImage(imageSize, 8, 1);

	// Points
	cv::Mat ptsI = cv::Mat(nPts, 2, CV_32FC1, pts_py_1->data);
	cv::Mat ptsJ = cv::Mat(nPts, 2, CV_32FC1, pts_py_2->data);

	points[0] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // template
	points[1] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // target
	points[2] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // forward-backward

	for(int i = 0; i < nPts; i++) {
		points[0][i].x = ptsI.at<float>(i, 0); points[0][i].y = ptsI.at<float>(i, 1);
		points[1][i].x = ptsJ.at<float>(i, 0); points[1][i].y = ptsJ.at<float>(i, 1);
		points[2][i].x = ptsI.at<float>(i, 0); points[2][i].y = ptsI.at<float>(i, 1);
	}
	float *fb = (float*)cvAlloc(nPts*sizeof(float));
	char  *status = (char*)cvAlloc(nPts);
	cvCalcOpticalFlowPyrLK(IMG[I], IMG[J], PYR[I], PYR[J], points[0],
		points[1], nPts, cvSize(win_size, win_size), Level, status, 0,
		cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03), CV_LKFLOW_INITIAL_GUESSES);
	PySys_WriteStdout("Completed forward flow\n");
	cvCalcOpticalFlowPyrLK(IMG[J], IMG[I], PYR[J], PYR[I], points[1],
		points[2], nPts, cvSize(win_size, win_size), Level, status, 0,
		cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03),
		CV_LKFLOW_INITIAL_GUESSES | CV_LKFLOW_PYR_A_READY | CV_LKFLOW_PYR_B_READY);
	PySys_WriteStdout("Completed backward flow\n");

	float *ncc = (float*)cvAlloc(nPts*sizeof(float));
	normCrossCorrelation(IMG[I], IMG[J], points[0], points[1], nPts, status, ncc, Winsize, CV_TM_CCOEFF_NORMED);
	PySys_WriteStdout("Completed NCC computation \n");

	//float *ssd = (float*)cvAlloc(nPts*sizeof(float));
	//normCrossCorrelation(IMG[I],IMG[J],points[0],points[1],nPts, status, ssd, Winsize,CV_TM_SQDIFF);

	euclideanDistance(points[0], points[2], fb, nPts);
	PySys_WriteStdout("Completed Euclidean distance computation\n");

	// Output
	int dims[] = { 4, nPts };
	PyArrayObject *output_py = (PyArrayObject *)PyArray_FromDims(2, dims, NPY_FLOAT);
	cv::Mat output = cv::Mat(nPts, 4, CV_32FC1, output_py->data);
	float nan = std::numeric_limits<float>::quiet_NaN();
	//float inf = std::numeric_limits<float>::infinity();
	for(int i = 0; i < nPts; i++) {
		if(status[i] == 1) {
			output.at<float>(i, 0) = points[1][i].x;
			output.at<float>(i, 1) = points[1][i].y;
			output.at<float>(i, 2) = fb[i];
			output.at<float>(i, 3) = ncc[i];
		} else {
			output.at<float>(i, 0) = nan;
			output.at<float>(i, 1) = nan;
			output.at<float>(i, 2) = nan;
			output.at<float>(i, 3) = nan;
		}
	}
	PySys_WriteStdout("Completed writing to output matrix\n");

	mtf::utils::drawPts<float>(img_1, ptsI, cv::Scalar(0, 0, 0), 2);
	mtf::utils::drawPts<float>(img_2, ptsJ, cv::Scalar(0, 0, 0), 2);
	std::vector<cv::Mat> img_list;
	img_list.push_back(img_1);
	img_list.push_back(img_2);
	cv::Mat stacked_img = mtf::utils::stackImages(img_list);
	cv::imshow("Input Images", stacked_img);
	if(cv::waitKey(100) == 27) {
		Py_Exit(0);
	}
	mtf::utils::printMatrixToFile<float>(ptsI, nullptr, "ptsI.txt", "%.4f");
	mtf::utils::printMatrixToFile<float>(ptsJ, nullptr, "ptsJ.txt", "%.4f");

	// clean up
	for(int i = 0; i < MAX_IMG; i++) {
		//! sharing memory with Python array
		//cvReleaseImage(&(IMG[i]));
		cvReleaseImage(&(PYR[i]));
	}
	free(IMG);
	free(PYR);
	PySys_WriteStdout("Completed cleaning up\n");
	return Py_BuildValue("O", output_py);
}
<|endoftext|>


<commit_before>/*
 *
 */

#include <cmath>
#include <algorithm>

#include "PowerlawDegreeSequence.h"
#include "../auxiliary/Random.h"
#include "../auxiliary/NumericTools.h"

NetworKit::PowerlawDegreeSequence::PowerlawDegreeSequence(NetworKit::count minDeg, NetworKit::count maxDeg, double gamma) :
	minDeg(minDeg), maxDeg(maxDeg), gamma(gamma), hasRun(false) {
	if (minDeg > maxDeg) throw std::runtime_error("Error: minDeg must not be larger than maxDeg");
	if (gamma > -1) throw std::runtime_error("Error: gamma must be lower than -1");
}

NetworKit::PowerlawDegreeSequence::PowerlawDegreeSequence(const std::vector< double > &degreeSequence) : minDeg(std::numeric_limits<count>::max()), maxDeg(std::numeric_limits<count>::min()) {
	count sum = 0;
	for (auto &d : degreeSequence) {
		if (d < minDeg) minDeg = d;
		if (d > maxDeg) maxDeg = d;
		sum += d;
	}

	double avg = sum * 1.0 / degreeSequence.size();

	setGammaFromAverageDegree(avg);
}

NetworKit::PowerlawDegreeSequence::PowerlawDegreeSequence(const NetworKit::Graph &g) : minDeg(std::numeric_limits<count>::max()), maxDeg(std::numeric_limits<count>::min()) {
	count sum = 0;
	g.forNodes([&](node u) {
		count d = g.degree(u);
		if (d < minDeg) minDeg = d;
		if (d > maxDeg) maxDeg = d;
		sum += d;
	});

	double avg = sum * 1.0 / g.numberOfNodes();

	setGammaFromAverageDegree(avg);
}

void NetworKit::PowerlawDegreeSequence::setMinimumDegree(NetworKit::count minDeg) {
	this->minDeg = minDeg;
	hasRun = false;
}

void NetworKit::PowerlawDegreeSequence::setGamma(double gamma) {
	this->gamma = gamma;
	hasRun = false;
}

void NetworKit::PowerlawDegreeSequence::setMinimumFromAverageDegree(double avgDeg) {
	count dmin_l = 1;
	count dmin_r = maxDeg;
	setMinimumDegree(dmin_l); run();
	double average_l = getExpectedAverageDegree();
	double average_r = maxDeg;

	if (average_l > avgDeg) {
		throw std::runtime_error("The average degree is too low");
	}

	if (average_r < avgDeg) {
		throw std::runtime_error("The average degree must not be higher than the maximum degree");
	}

	while (dmin_l + 1 < dmin_r) {
		setMinimumDegree((dmin_r + dmin_l) * 0.5); run();
		double avg = getExpectedAverageDegree();

		TRACE("Trying minDeg ", minDeg, ", this gives average ", avg, ", which should be between ", average_r, " and ", average_l);

		if (avg > avgDeg) {
			average_r = avg;
			dmin_r = minDeg;
		} else {
			average_l = avg;
			dmin_l = minDeg;
		}
	}

	if (avgDeg - average_l < average_r - avgDeg) {
		minDeg = dmin_l;
	} else {
		minDeg = dmin_r;
	}

	hasRun = false;
}

void NetworKit::PowerlawDegreeSequence::setGammaFromAverageDegree(double avgDeg, double minGamma, double maxGamma) {
	double gamma_l = maxGamma;
	double gamma_r = minGamma;
	setGamma(gamma_l); run();
	double average_l = getExpectedAverageDegree();
	setGamma(gamma_r); run();
	double average_r = getExpectedAverageDegree();

	// Note: r is the larger expected average degree!
	if (avgDeg > average_r) {
		setGamma(gamma_r);
		return;
	}

	if (avgDeg < average_l) {
		setGamma(gamma_l);
		return;
	}

	while (gamma_l + 0.001 < gamma_r) {
		setGamma((gamma_r + gamma_l) * 0.5); run();

		double avg = getExpectedAverageDegree();

		if (avg > avgDeg) {
			average_r = avg;
			gamma_r = gamma;
		} else {
			average_l = avg;
			gamma_l = gamma;
		}
	}

	if (avgDeg - average_l < average_r - avgDeg) {
		setGamma(gamma_l);
	} else {
		setGamma(gamma_r);
	}
}

NetworKit::count NetworKit::PowerlawDegreeSequence::getMinimumDegree() const {
	return minDeg;
}

void NetworKit::PowerlawDegreeSequence::run() {
	cumulativeProbability.clear();
	cumulativeProbability.reserve(maxDeg - minDeg + 1);

	double sum = 0;

	for (double d = minDeg; d <= maxDeg; ++d) {
		sum += std::pow(d, gamma);
		cumulativeProbability.push_back(sum);
	}

	for (double & prob : cumulativeProbability) {
		prob /= sum;
	}

	hasRun= true;
}

double NetworKit::PowerlawDegreeSequence::getExpectedAverageDegree() const {
	if (!hasRun) throw std::runtime_error("Error: run needs to be called first");

	double average = cumulativeProbability[0] * minDeg;
	for (count i = 1; i < cumulativeProbability.size(); ++i) {
		average += (cumulativeProbability[i] - cumulativeProbability[i-1]) * (i + minDeg);
	}

	return average;
}

std::vector< NetworKit::count > NetworKit::PowerlawDegreeSequence::getDegreeSequence(NetworKit::count numNodes) const {
	std::vector<count> degreeSequence;

	if (!hasRun) throw std::runtime_error("Error: run needs to be called first");

	degreeSequence.reserve(numNodes);
	count degreeSum = 0;

	for (count i = 0; i < numNodes; ++i) {
		degreeSequence.push_back(getDegree());
		degreeSum += degreeSequence.back();
	}

	if (degreeSum % 2 != 0) {
		(*std::max_element(degreeSequence.begin(), degreeSequence.end()))--;
	}

	return degreeSequence;
}

NetworKit::count NetworKit::PowerlawDegreeSequence::getDegree() const {
	if (!hasRun) throw std::runtime_error("Error: run needs to be called first");

	return std::distance(cumulativeProbability.begin(), std::lower_bound(cumulativeProbability.begin(), cumulativeProbability.end(), Aux::Random::probability())) + minDeg;
}
<commit_msg>PowerlawDegreeSequence: reverse internal order to avoid rounding problems<commit_after>/*
 *
 */

#include <cmath>
#include <algorithm>

#include "PowerlawDegreeSequence.h"
#include "../auxiliary/Random.h"
#include "../auxiliary/NumericTools.h"

NetworKit::PowerlawDegreeSequence::PowerlawDegreeSequence(NetworKit::count minDeg, NetworKit::count maxDeg, double gamma) :
	minDeg(minDeg), maxDeg(maxDeg), gamma(gamma), hasRun(false) {
	if (minDeg > maxDeg) throw std::runtime_error("Error: minDeg must not be larger than maxDeg");
	if (gamma > -1) throw std::runtime_error("Error: gamma must be lower than -1");
}

NetworKit::PowerlawDegreeSequence::PowerlawDegreeSequence(const std::vector< double > &degreeSequence) : minDeg(std::numeric_limits<count>::max()), maxDeg(std::numeric_limits<count>::min()) {
	count sum = 0;
	for (auto &d : degreeSequence) {
		if (d < minDeg) minDeg = d;
		if (d > maxDeg) maxDeg = d;
		sum += d;
	}

	double avg = sum * 1.0 / degreeSequence.size();

	setGammaFromAverageDegree(avg);
}

NetworKit::PowerlawDegreeSequence::PowerlawDegreeSequence(const NetworKit::Graph &g) : minDeg(std::numeric_limits<count>::max()), maxDeg(std::numeric_limits<count>::min()) {
	count sum = 0;
	g.forNodes([&](node u) {
		count d = g.degree(u);
		if (d < minDeg) minDeg = d;
		if (d > maxDeg) maxDeg = d;
		sum += d;
	});

	double avg = sum * 1.0 / g.numberOfNodes();

	setGammaFromAverageDegree(avg);
}

void NetworKit::PowerlawDegreeSequence::setMinimumDegree(NetworKit::count minDeg) {
	this->minDeg = minDeg;
	hasRun = false;
}

void NetworKit::PowerlawDegreeSequence::setGamma(double gamma) {
	this->gamma = gamma;
	hasRun = false;
}

void NetworKit::PowerlawDegreeSequence::setMinimumFromAverageDegree(double avgDeg) {
	count dmin_l = 1;
	count dmin_r = maxDeg;
	setMinimumDegree(dmin_l); run();
	double average_l = getExpectedAverageDegree();
	double average_r = maxDeg;

	if (average_l > avgDeg) {
		throw std::runtime_error("The average degree is too low");
	}

	if (average_r < avgDeg) {
		throw std::runtime_error("The average degree must not be higher than the maximum degree");
	}

	while (dmin_l + 1 < dmin_r) {
		setMinimumDegree((dmin_r + dmin_l) * 0.5); run();
		double avg = getExpectedAverageDegree();

		TRACE("Trying minDeg ", minDeg, ", this gives average ", avg, ", which should be between ", average_r, " and ", average_l);

		if (avg > avgDeg) {
			average_r = avg;
			dmin_r = minDeg;
		} else {
			average_l = avg;
			dmin_l = minDeg;
		}
	}

	if (avgDeg - average_l < average_r - avgDeg) {
		minDeg = dmin_l;
	} else {
		minDeg = dmin_r;
	}

	hasRun = false;
}

void NetworKit::PowerlawDegreeSequence::setGammaFromAverageDegree(double avgDeg, double minGamma, double maxGamma) {
	double gamma_l = maxGamma;
	double gamma_r = minGamma;
	setGamma(gamma_l); run();
	double average_l = getExpectedAverageDegree();
	setGamma(gamma_r); run();
	double average_r = getExpectedAverageDegree();

	// Note: r is the larger expected average degree!
	if (avgDeg > average_r) {
		setGamma(gamma_r);
		return;
	}

	if (avgDeg < average_l) {
		setGamma(gamma_l);
		return;
	}

	while (gamma_l + 0.001 < gamma_r) {
		setGamma((gamma_r + gamma_l) * 0.5); run();

		double avg = getExpectedAverageDegree();

		if (avg > avgDeg) {
			average_r = avg;
			gamma_r = gamma;
		} else {
			average_l = avg;
			gamma_l = gamma;
		}
	}

	if (avgDeg - average_l < average_r - avgDeg) {
		setGamma(gamma_l);
	} else {
		setGamma(gamma_r);
	}
}

NetworKit::count NetworKit::PowerlawDegreeSequence::getMinimumDegree() const {
	return minDeg;
}

void NetworKit::PowerlawDegreeSequence::run() {
	cumulativeProbability.clear();
	cumulativeProbability.reserve(maxDeg - minDeg + 1);

	double sum = 0;

	for (double d = maxDeg; d >= minDeg; --d) {
		sum += std::pow(d, gamma);
		cumulativeProbability.push_back(sum);
	}

	for (double & prob : cumulativeProbability) {
		prob /= sum;
	}

	cumulativeProbability.back() = 1.0;

	hasRun= true;
}

double NetworKit::PowerlawDegreeSequence::getExpectedAverageDegree() const {
	if (!hasRun) throw std::runtime_error("Error: run needs to be called first");

	double average = cumulativeProbability[0] * maxDeg;
	for (count i = 1; i < cumulativeProbability.size(); ++i) {
		average += (cumulativeProbability[i] - cumulativeProbability[i-1]) * (maxDeg - i);
	}

	return average;
}

std::vector< NetworKit::count > NetworKit::PowerlawDegreeSequence::getDegreeSequence(NetworKit::count numNodes) const {
	std::vector<count> degreeSequence;

	if (!hasRun) throw std::runtime_error("Error: run needs to be called first");

	degreeSequence.reserve(numNodes);
	count degreeSum = 0;

	for (count i = 0; i < numNodes; ++i) {
		degreeSequence.push_back(getDegree());
		degreeSum += degreeSequence.back();
	}

	if (degreeSum % 2 != 0) {
		(*std::max_element(degreeSequence.begin(), degreeSequence.end()))--;
	}

	return degreeSequence;
}

NetworKit::count NetworKit::PowerlawDegreeSequence::getDegree() const {
	if (!hasRun) throw std::runtime_error("Error: run needs to be called first");

	return maxDeg - std::distance(cumulativeProbability.begin(), std::lower_bound(cumulativeProbability.begin(), cumulativeProbability.end(), Aux::Random::probability()));
}
<|endoftext|>


<commit_before>/**
 * @file
 */
#include "libbirch/memory.hpp"

#include "libbirch/Any.hpp"
#include "libbirch/Label.hpp"
#include "libbirch/Shared.hpp"

/**
 * Type for object lists in cycle collection.
 */
using object_list = std::vector<libbirch::Any*,libbirch::Allocator<libbirch::Any*>>;

/**
 * Get the possible roots list for the current thread.
 */
static object_list& get_thread_possible_roots() {
  static std::vector<object_list,libbirch::Allocator<object_list>> objects(
      libbirch::get_max_threads());
  return objects[libbirch::get_thread_num()];
}

/**
 * Get the unreachable list for the current thread.
 */
static object_list& get_thread_unreachable() {
  static std::vector<object_list,libbirch::Allocator<object_list>> objects(
      libbirch::get_max_threads());
  return objects[libbirch::get_thread_num()];
}

/**
 * Create the heap.
 */
static char* make_heap() {
  #if !ENABLE_MEMORY_POOL
  return nullptr;
  #else
  /* determine a preferred size of the heap based on total physical memory */
  size_t size = sysconf(_SC_PAGE_SIZE);
  size_t npages = sysconf(_SC_PHYS_PAGES);
  size_t n = 8u*npages*size;

  /* attempt to allocate this amount, successively halving until
   * successful */
  void* ptr = nullptr;
  int res = 0;
  do {
    res = posix_memalign(&ptr, 64ull, n);
    n >>= 1;
  } while (res > 0 && n > 0u);
  assert(ptr);

  return (char*)ptr;
  #endif
}

/**
 * Create the root label.
 */
static auto make_root_label() {
  auto label = new libbirch::Label();
  label->incShared();
  return label;
}

libbirch::ExitBarrierLock libbirch::finish_lock;
libbirch::ExitBarrierLock libbirch::freeze_lock;

libbirch::Atomic<char*> libbirch::heap(make_heap());
libbirch::Label* const libbirch::root_label(make_root_label());

libbirch::Pool& libbirch::pool(const int i) {
  static libbirch::Pool* pools = new libbirch::Pool[64*get_max_threads()];
  return pools[i];
}

void* libbirch::allocate(const size_t n) {
  assert(n > 0u);

  #if !ENABLE_MEMORY_POOL
  return std::malloc(n);
  #else
  int tid = get_thread_num();
  int i = bin(n);       // determine which pool
  auto ptr = pool(64*tid + i).pop();  // attempt to reuse from this pool
  if (!ptr) {           // otherwise allocate new
    size_t m = unbin(i);
    ptr = (heap += m) - m;
  }
  assert(ptr);
  return ptr;
  #endif
}

void libbirch::deallocate(void* ptr, const size_t n, const int tid) {
  assert(ptr);
  assert(n > 0u);
  assert(tid < get_max_threads());

  #if !ENABLE_MEMORY_POOL
  std::free(ptr);
  #else
  int i = bin(n);
  pool(64*tid + i).push(ptr);
  #endif
}

void libbirch::deallocate(void* ptr, const unsigned n, const int tid) {
  assert(ptr);
  assert(n > 0u);
  assert(tid < get_max_threads());

  #if !ENABLE_MEMORY_POOL
  std::free(ptr);
  #else
  int i = bin(n);
  pool(64*tid + i).push(ptr);
  #endif
}

void* libbirch::reallocate(void* ptr1, const size_t n1, const int tid1,
    const size_t n2) {
  assert(ptr1);
  assert(n1 > 0u);
  assert(tid1 < get_max_threads());
  assert(n2 > 0u);

  #if !ENABLE_MEMORY_POOL
  return std::realloc(ptr1, n2);
  #else
  int i1 = bin(n1);
  int i2 = bin(n2);
  void* ptr2 = ptr1;
  if (i1 != i2) {
    /* can't continue using current allocation */
    ptr2 = allocate(n2);
    if (ptr1 && ptr2) {
      std::memcpy(ptr2, ptr1, std::min(n1, n2));
    }
    deallocate(ptr1, n1, tid1);
  }
  return ptr2;
  #endif
}

void libbirch::register_possible_root(Any* o) {
  assert(o);
  o->incMemo();
  get_thread_possible_roots().emplace_back(o);
}

void libbirch::register_unreachable(Any* o) {
  assert(o);
  o->incMemo();
  get_thread_unreachable().emplace_back(o);
}

void libbirch::collect() {
  #pragma omp parallel num_threads(get_max_threads())
  {
    /* mark */
    auto& possible_roots = get_thread_possible_roots();
    for (auto& o : possible_roots) {
      if (o) {
        if (o->isPossibleRoot()) {
          o->mark();
        } else {
          o->decMemo();
          o = nullptr;
        }
      }
    }
    #pragma omp barrier

    /* scan */
    for (auto& o : possible_roots) {
      if (o) {
        o->scan();
      }
    }
    #pragma omp barrier

    /* collect */
    for (auto& o : possible_roots) {
      if (o) {
        o->collect();
        o->decMemo();
        o = nullptr;
      }
    }
    possible_roots.clear();

    /* destroy the objects indicated during collect */
    auto& unreachable = get_thread_unreachable();
    for (auto& o : unreachable) {
      o->destroy();
      o->decMemo();
    }

    unreachable.clear();
  }
}

void libbirch::trim(Any* o) {
  auto& possible_roots = get_thread_possible_roots();
  while (!possible_roots.empty()) {
    auto ptr = possible_roots.back();
    if (ptr == o || !ptr->isPossibleRoot()) {
      possible_roots.pop_back();
      ptr->decMemo();
    } else {
      return;
    }
  }
}
<commit_msg>Fixed memory leak caused by one more memo count than necessary during collect() operation.<commit_after>/**
 * @file
 */
#include "libbirch/memory.hpp"

#include "libbirch/Any.hpp"
#include "libbirch/Label.hpp"
#include "libbirch/Shared.hpp"

/**
 * Type for object lists in cycle collection.
 */
using object_list = std::vector<libbirch::Any*,libbirch::Allocator<libbirch::Any*>>;

/**
 * Get the possible roots list for the current thread.
 */
static object_list& get_thread_possible_roots() {
  static std::vector<object_list,libbirch::Allocator<object_list>> objects(
      libbirch::get_max_threads());
  return objects[libbirch::get_thread_num()];
}

/**
 * Get the unreachable list for the current thread.
 */
static object_list& get_thread_unreachable() {
  static std::vector<object_list,libbirch::Allocator<object_list>> objects(
      libbirch::get_max_threads());
  return objects[libbirch::get_thread_num()];
}

/**
 * Create the heap.
 */
static char* make_heap() {
  #if !ENABLE_MEMORY_POOL
  return nullptr;
  #else
  /* determine a preferred size of the heap based on total physical memory */
  size_t size = sysconf(_SC_PAGE_SIZE);
  size_t npages = sysconf(_SC_PHYS_PAGES);
  size_t n = 8u*npages*size;

  /* attempt to allocate this amount, successively halving until
   * successful */
  void* ptr = nullptr;
  int res = 0;
  do {
    res = posix_memalign(&ptr, 64ull, n);
    n >>= 1;
  } while (res > 0 && n > 0u);
  assert(ptr);

  return (char*)ptr;
  #endif
}

/**
 * Create the root label.
 */
static auto make_root_label() {
  auto label = new libbirch::Label();
  label->incShared();
  return label;
}

libbirch::ExitBarrierLock libbirch::finish_lock;
libbirch::ExitBarrierLock libbirch::freeze_lock;

libbirch::Atomic<char*> libbirch::heap(make_heap());
libbirch::Label* const libbirch::root_label(make_root_label());

libbirch::Pool& libbirch::pool(const int i) {
  static libbirch::Pool* pools = new libbirch::Pool[64*get_max_threads()];
  return pools[i];
}

void* libbirch::allocate(const size_t n) {
  assert(n > 0u);

  #if !ENABLE_MEMORY_POOL
  return std::malloc(n);
  #else
  int tid = get_thread_num();
  int i = bin(n);       // determine which pool
  auto ptr = pool(64*tid + i).pop();  // attempt to reuse from this pool
  if (!ptr) {           // otherwise allocate new
    size_t m = unbin(i);
    ptr = (heap += m) - m;
  }
  assert(ptr);
  return ptr;
  #endif
}

void libbirch::deallocate(void* ptr, const size_t n, const int tid) {
  assert(ptr);
  assert(n > 0u);
  assert(tid < get_max_threads());

  #if !ENABLE_MEMORY_POOL
  std::free(ptr);
  #else
  int i = bin(n);
  pool(64*tid + i).push(ptr);
  #endif
}

void libbirch::deallocate(void* ptr, const unsigned n, const int tid) {
  assert(ptr);
  assert(n > 0u);
  assert(tid < get_max_threads());

  #if !ENABLE_MEMORY_POOL
  std::free(ptr);
  #else
  int i = bin(n);
  pool(64*tid + i).push(ptr);
  #endif
}

void* libbirch::reallocate(void* ptr1, const size_t n1, const int tid1,
    const size_t n2) {
  assert(ptr1);
  assert(n1 > 0u);
  assert(tid1 < get_max_threads());
  assert(n2 > 0u);

  #if !ENABLE_MEMORY_POOL
  return std::realloc(ptr1, n2);
  #else
  int i1 = bin(n1);
  int i2 = bin(n2);
  void* ptr2 = ptr1;
  if (i1 != i2) {
    /* can't continue using current allocation */
    ptr2 = allocate(n2);
    if (ptr1 && ptr2) {
      std::memcpy(ptr2, ptr1, std::min(n1, n2));
    }
    deallocate(ptr1, n1, tid1);
  }
  return ptr2;
  #endif
}

void libbirch::register_possible_root(Any* o) {
  assert(o);
  o->incMemo();
  get_thread_possible_roots().emplace_back(o);
}

void libbirch::register_unreachable(Any* o) {
  assert(o);
  //o->incMemo();
  // ^ no need to increment the memo count here; any object in this list has
  //   had its shared count decremented to zero, but no the additional memo
  //   count removed, just yet
  get_thread_unreachable().emplace_back(o);
}

void libbirch::collect() {
  #pragma omp parallel num_threads(get_max_threads())
  {
    /* mark */
    auto& possible_roots = get_thread_possible_roots();
    for (auto& o : possible_roots) {
      if (o) {
        if (o->isPossibleRoot()) {
          o->mark();
        } else {
          o->decMemo();
          o = nullptr;
        }
      }
    }
    #pragma omp barrier

    /* scan */
    for (auto& o : possible_roots) {
      if (o) {
        o->scan();
      }
    }
    #pragma omp barrier

    /* collect */
    for (auto& o : possible_roots) {
      if (o) {
        o->collect();
        o->decMemo();
        o = nullptr;
      }
    }
    possible_roots.clear();

    /* destroy the objects indicated during collect */
    auto& unreachable = get_thread_unreachable();
    for (auto& o : unreachable) {
      o->destroy();
      o->decMemo();  // removes last memo count
    }

    unreachable.clear();
  }
}

void libbirch::trim(Any* o) {
  auto& possible_roots = get_thread_possible_roots();
  while (!possible_roots.empty()) {
    auto ptr = possible_roots.back();
    if (ptr == o || !ptr->isPossibleRoot()) {
      possible_roots.pop_back();
      ptr->decMemo();
    } else {
      return;
    }
  }
}
<|endoftext|>


<commit_before>#include <StdAfx.h>
#include <MrMapi/MMNamedProps.h>
#include <MrMapi/mmcli.h>
#include <core/mapi/processor/mapiProcessor.h>
#include <core/mapi/extraPropTags.h>
#include <core/smartview/SmartView.h>
#include <core/utility/strings.h>
#include <core/utility/registry.h>
#include <core/utility/output.h>
#include <core/mapi/mapiFunctions.h>
#include <core/mapi/cache/namedProps.h>
#include <core/addin/mfcmapi.h>
#include <chrono>
#include <unordered_set>
#include <core/interpret/guid.h>

template <typename... Arguments>
void WriteOutput(_In_opt_ FILE* fOut, _Printf_format_string_ LPCWSTR szMsg, Arguments&&... args)
{
	const auto szString = strings::format(szMsg, std::forward<Arguments>(args)...);
	if (fOut)
	{
		output::Output(output::dbgLevel::NoDebug, fOut, false, szString);
	}
	else
	{
		wprintf(L"%ws", szString.c_str());
	}
}

void PrintGuid(FILE* fOut, const GUID& lpGuid)
{
	WriteOutput(
		fOut,
		L"%.8lX-%.4X-%.4X-%.2X%.2X-%.2X%.2X%.2X%.2X%.2X%.2X",
		lpGuid.Data1,
		lpGuid.Data2,
		lpGuid.Data3,
		lpGuid.Data4[0],
		lpGuid.Data4[1],
		lpGuid.Data4[2],
		lpGuid.Data4[3],
		lpGuid.Data4[4],
		lpGuid.Data4[5],
		lpGuid.Data4[6],
		lpGuid.Data4[7]);
}

/// <summary>
/// Hash implementation for GUIDs so they can be stored in std::unordered_list
/// </summary>
class GuidHasher
{
public:
	size_t operator()(const GUID& guid) const
	{
		std::uint32_t hash =
			guid.Data1 ^ (((int) guid.Data2 << 16) | (int) guid.Data3) ^ (((int) guid.Data4[2] << 24) | guid.Data4[7]);
		return std::hash<std::uint32_t>()(hash);
	}
};

/// <summary>
/// Comparer class used for comparing two GUIDs (whether lhs < rhs).
/// Used with std::map where GUID is the key
/// </summary>
class GuidLess
{
public:
	bool operator()(const GUID& lhs, const GUID& rhs) const { return memcmp(&lhs, &rhs, sizeof(GUID)) < 0; }
};

/// <summary>
/// Analyzes named properties to discover patterns that indicate incorrect usage of named properties by applications.
/// </summary>
/// <param name="fOut">The output file pointer</param>
/// <param name="nameToNumberMap">The named property list</param>
void AnalyzeNamedProps(
	_In_opt_ FILE* fOut,
	std::vector<std::shared_ptr<cache::namedPropCacheEntry>> const& nameToNumberMap)
{
	const std::uint32_t namedPropsQuota = 16384;
	const std::uint32_t NamedPropsLeakPatternCheckPercentageThreshold = 30;
	const std::uint32_t NamedPropsLeakPatternGuidPercentageThreshold = 20;
	const std::uint32_t NamedPropsLeakPatternGuidPercentageThresholdForInternetHeaders = 60;
	const std::uint32_t NamedPropsLeakPatternNamePrefixLength = 10;
	const std::uint32_t NamedPropsLeakPatternNamePrefixPercentageThreshold = 10;

	std::unordered_set<GUID, GuidHasher> leakPatternGuids;
	std::unordered_set<std::wstring> leakPatternNamePrefixes;

	// Simple detection for some misbehaving applications which cause named property exhaustion.
	// This detection is not comprehensive, it just attempts to recognize two known patterns.
	// If the application doesn't follow any of those two patterns (e.g. just registers random names with random guids)
	// then we won't detect the pattern, and manual analysis will have to be done.
	if (nameToNumberMap.size() > namedPropsQuota / 100 * NamedPropsLeakPatternCheckPercentageThreshold)
	{
		std::map<GUID, int, GuidLess> guidCounts;
		std::map<std::wstring, int> namePrefixCounts;

		// Loop through all properties and discovery leaky GUID patterns and leaky prefixes
		for (const auto& entry : nameToNumberMap)
		{
			const auto registeredPropName = entry->getMapiNameId();
			const auto isInternetHeadersNamespace =
				memcmp(registeredPropName->lpguid, &guid::PS_INTERNET_HEADERS, sizeof(GUID)) == 0;

			// Check for a GUID pattern. We consider abnormal if we see more than
			// 2K names within the same GUID namespace. We allow larger limit for InternetHeaders
			// because some mailboxes migrated from older versions have more properties in this namespace.
			int count = ++guidCounts[*registeredPropName->lpguid];

			if ((isInternetHeadersNamespace &&
				 count > namedPropsQuota / 100 * NamedPropsLeakPatternGuidPercentageThresholdForInternetHeaders) ||
				(false == isInternetHeadersNamespace &&
				 count > namedPropsQuota / 100 * NamedPropsLeakPatternGuidPercentageThreshold))
			{
				leakPatternGuids.emplace(*registeredPropName->lpguid);
			}

			// If this is a string name and name is long enough, check for a name prefix pattern. We consider abnormal if we see more than
			// 1K names with the same 10-character prefix.
			if (registeredPropName->ulKind == MNID_STRING && registeredPropName->Kind.lpwstrName != nullptr)
			{
				std::wstring namePrefix = registeredPropName->Kind.lpwstrName;
				if (namePrefix.size() > NamedPropsLeakPatternNamePrefixLength)
				{
					namePrefix = namePrefix.substr(0, NamedPropsLeakPatternNamePrefixLength);
				}

				count = ++namePrefixCounts[namePrefix];
				if (count > namedPropsQuota / 100 * NamedPropsLeakPatternNamePrefixPercentageThreshold)
				{
					leakPatternNamePrefixes.emplace(namePrefix);
				}
			}
		}
	}

	// Print out leaky property-set GUIDs
	WriteOutput(fOut, L"\nDetected %zu property sets with a large number of properties.\n", leakPatternGuids.size());
	if (!leakPatternGuids.empty())
	{
		WriteOutput(
			fOut,
			L"This typically indicates the incorrect use of named properties by a custom application.\nCheck the full "
			L"list of properties in the property set(s) listed below to help identify the application at fault.\n");
	}

	for (const auto& guid : leakPatternGuids)
	{
		const auto guidString = guid::GUIDToStringAndName(guid);
		WriteOutput(fOut, L"%ws\n", guidString.c_str());
	}

	// Print out leaky prefixes
	WriteOutput(
		fOut,
		L"\nDetected %zu large sets of unique properties sharing a common prefix.\n",
		leakPatternNamePrefixes.size());
	if (!leakPatternNamePrefixes.empty())
	{
		WriteOutput(fOut, L"This typically indicates the incorrect use of named properties by a custom application.\n");
	}

	for (const auto& prefix : leakPatternNamePrefixes)
	{
		WriteOutput(fOut, L"%ws\n", prefix.c_str());
	}
}

/// <summary>
/// Performs the full named property analysis and output.
/// </summary>
/// <param name="lpSession">The MAPI session.</param>
/// <param name="lpMDB">The MAPI message store.</param>
void DoNamedProps(_In_opt_ LPMAPISESSION lpSession, _In_opt_ LPMDB lpMDB)
{
	if (!lpSession || !lpMDB) return;
	registry::cacheNamedProps = false;

	// Ignore the reg key that disables smart view parsing
	registry::doSmartView = true;

	// See if they have specified an output file
	FILE* fOut = nullptr;
	const auto output = cli::switchOutput[0];
	if (!output.empty())
	{
		fOut = output::MyOpenFileMode(output, L"wb");
		if (!fOut)
		{
			wprintf(L"Cannot open output file %ws\n", output.c_str());
			return exit(-1);
		}
	}

	wprintf(L"Dumping named properties...\n\n");

	// Print the name of the profile and the parsed store entry-id so we can tell which mailbox this is
	const auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
	WriteOutput(fOut, L"Timestamp: %hs\n", ctime(&now));
	WriteOutput(fOut, L"Profile Name: %ws\n", mapi::GetProfileName(lpSession).c_str());
	LPSPropValue lpStoreEntryId = nullptr;
	const auto result = WC_H(HrGetOneProp(lpMDB, PR_STORE_ENTRYID, &lpStoreEntryId));
	if (SUCCEEDED(result))
	{
		const auto block = smartview::InterpretBinary(lpStoreEntryId->Value.bin, parserType::ENTRYID, lpMDB);
		const auto storeEntryId = strings::StripCarriage(block->toString());
		WriteOutput(fOut, L"%ws\n\n", storeEntryId.c_str());

		MAPIFreeBuffer(lpStoreEntryId);
	}

	auto names = cache::GetNamesFromIDs(lpMDB, nullptr, 0);

	// Start by analyzing the properties
	AnalyzeNamedProps(fOut, names);

	// Now output all of them
	WriteOutput(fOut, L"\nProperty List:\n");
	std::sort(
		names.begin(),
		names.end(),
		[](std::shared_ptr<cache::namedPropCacheEntry>& i, std::shared_ptr<cache::namedPropCacheEntry>& j) {
			// If the Property set GUIDs don't match, sort by that
			const auto iNameId = i->getMapiNameId();
			const auto jNameId = j->getMapiNameId();
			const auto res = memcmp(iNameId->lpguid, jNameId->lpguid, sizeof(GUID));
			if (res) return res < 0;

			// If they are different kinds, use that next
			if (iNameId->ulKind != jNameId->ulKind)
			{
				return iNameId->ulKind < jNameId->ulKind;
			}

			switch (iNameId->ulKind)
			{
			case MNID_ID:
				return iNameId->Kind.lID < jNameId->Kind.lID;
			case MNID_STRING:
				return std::wstring(iNameId->Kind.lpwstrName) < std::wstring(jNameId->Kind.lpwstrName);
			}

			// This shouldn't ever actually hit
			return i->getPropID() < j->getPropID();
		});

	for (const auto& name : names)
	{
		WriteOutput(fOut, L"[%08X] (", PROP_TAG(PT_UNSPECIFIED, name->getPropID()));
		const auto nameId = name->getMapiNameId();
		PrintGuid(fOut, *nameId->lpguid);
		switch (nameId->ulKind)
		{
		case MNID_ID:
			WriteOutput(fOut, L":0x%04X)\n", nameId->Kind.lID);
			break;

		case MNID_STRING:
			WriteOutput(fOut, L":%ws)\n", nameId->Kind.lpwstrName);
			break;
		}
	}

	wprintf(L"Completed.\n");
	if (fOut) fclose(fOut);
}<commit_msg>Split count variables in named prop analysis for clarity<commit_after>#include <StdAfx.h>
#include <MrMapi/MMNamedProps.h>
#include <MrMapi/mmcli.h>
#include <core/mapi/processor/mapiProcessor.h>
#include <core/mapi/extraPropTags.h>
#include <core/smartview/SmartView.h>
#include <core/utility/strings.h>
#include <core/utility/registry.h>
#include <core/utility/output.h>
#include <core/mapi/mapiFunctions.h>
#include <core/mapi/cache/namedProps.h>
#include <core/addin/mfcmapi.h>
#include <chrono>
#include <unordered_set>
#include <core/interpret/guid.h>

template <typename... Arguments>
void WriteOutput(_In_opt_ FILE* fOut, _Printf_format_string_ LPCWSTR szMsg, Arguments&&... args)
{
	const auto szString = strings::format(szMsg, std::forward<Arguments>(args)...);
	if (fOut)
	{
		output::Output(output::dbgLevel::NoDebug, fOut, false, szString);
	}
	else
	{
		wprintf(L"%ws", szString.c_str());
	}
}

void PrintGuid(FILE* fOut, const GUID& lpGuid)
{
	WriteOutput(
		fOut,
		L"%.8lX-%.4X-%.4X-%.2X%.2X-%.2X%.2X%.2X%.2X%.2X%.2X",
		lpGuid.Data1,
		lpGuid.Data2,
		lpGuid.Data3,
		lpGuid.Data4[0],
		lpGuid.Data4[1],
		lpGuid.Data4[2],
		lpGuid.Data4[3],
		lpGuid.Data4[4],
		lpGuid.Data4[5],
		lpGuid.Data4[6],
		lpGuid.Data4[7]);
}

/// <summary>
/// Hash implementation for GUIDs so they can be stored in std::unordered_list
/// </summary>
class GuidHasher
{
public:
	size_t operator()(const GUID& guid) const
	{
		std::uint32_t hash =
			guid.Data1 ^ (((int) guid.Data2 << 16) | (int) guid.Data3) ^ (((int) guid.Data4[2] << 24) | guid.Data4[7]);
		return std::hash<std::uint32_t>()(hash);
	}
};

/// <summary>
/// Comparer class used for comparing two GUIDs (whether lhs < rhs).
/// Used with std::map where GUID is the key
/// </summary>
class GuidLess
{
public:
	bool operator()(const GUID& lhs, const GUID& rhs) const { return memcmp(&lhs, &rhs, sizeof(GUID)) < 0; }
};

/// <summary>
/// Analyzes named properties to discover patterns that indicate incorrect usage of named properties by applications.
/// </summary>
/// <param name="fOut">The output file pointer</param>
/// <param name="nameToNumberMap">The named property list</param>
void AnalyzeNamedProps(
	_In_opt_ FILE* fOut,
	std::vector<std::shared_ptr<cache::namedPropCacheEntry>> const& nameToNumberMap)
{
	const std::uint32_t namedPropsQuota = 16384;
	const std::uint32_t NamedPropsLeakPatternCheckPercentageThreshold = 30;
	const std::uint32_t NamedPropsLeakPatternGuidPercentageThreshold = 20;
	const std::uint32_t NamedPropsLeakPatternGuidPercentageThresholdForInternetHeaders = 60;
	const std::uint32_t NamedPropsLeakPatternNamePrefixLength = 10;
	const std::uint32_t NamedPropsLeakPatternNamePrefixPercentageThreshold = 10;

	std::unordered_set<GUID, GuidHasher> leakPatternGuids;
	std::unordered_set<std::wstring> leakPatternNamePrefixes;

	// Simple detection for some misbehaving applications which cause named property exhaustion.
	// This detection is not comprehensive, it just attempts to recognize two known patterns.
	// If the application doesn't follow any of those two patterns (e.g. just registers random names with random guids)
	// then we won't detect the pattern, and manual analysis will have to be done.
	if (nameToNumberMap.size() > namedPropsQuota / 100 * NamedPropsLeakPatternCheckPercentageThreshold)
	{
		std::map<GUID, int, GuidLess> guidCounts;
		std::map<std::wstring, int> namePrefixCounts;

		// Loop through all properties and discovery leaky GUID patterns and leaky prefixes
		for (const auto& entry : nameToNumberMap)
		{
			const auto registeredPropName = entry->getMapiNameId();
			const auto isInternetHeadersNamespace =
				memcmp(registeredPropName->lpguid, &guid::PS_INTERNET_HEADERS, sizeof(GUID)) == 0;

			// Check for a GUID pattern. We consider abnormal if we see more than
			// 2K names within the same GUID namespace. We allow larger limit for InternetHeaders
			// because some mailboxes migrated from older versions have more properties in this namespace.

			// Increment and capture the new count
			const int guidCount = ++guidCounts[*registeredPropName->lpguid];

			if ((isInternetHeadersNamespace &&
				 guidCount > namedPropsQuota / 100 * NamedPropsLeakPatternGuidPercentageThresholdForInternetHeaders) ||
				(!isInternetHeadersNamespace &&
				 guidCount > namedPropsQuota / 100 * NamedPropsLeakPatternGuidPercentageThreshold))
			{
				leakPatternGuids.emplace(*registeredPropName->lpguid);
			}

			// If this is a string name and name is long enough, check for a name prefix pattern. We consider abnormal if we see more than
			// 1K names with the same 10-character prefix.
			if (registeredPropName->ulKind == MNID_STRING && registeredPropName->Kind.lpwstrName != nullptr)
			{
				std::wstring namePrefix = registeredPropName->Kind.lpwstrName;
				if (namePrefix.size() > NamedPropsLeakPatternNamePrefixLength)
				{
					namePrefix = namePrefix.substr(0, NamedPropsLeakPatternNamePrefixLength);
				}

				// Increment and capture the new count
				const int prefixCount = ++namePrefixCounts[namePrefix];
				if (prefixCount > namedPropsQuota / 100 * NamedPropsLeakPatternNamePrefixPercentageThreshold)
				{
					leakPatternNamePrefixes.emplace(namePrefix);
				}
			}
		}
	}

	// Print out leaky property-set GUIDs
	WriteOutput(fOut, L"\nDetected %zu property sets with a large number of properties.\n", leakPatternGuids.size());
	if (!leakPatternGuids.empty())
	{
		WriteOutput(
			fOut,
			L"This typically indicates the incorrect use of named properties by a custom application.\nCheck the full "
			L"list of properties in the property set(s) listed below to help identify the application at fault.\n");
	}

	for (const auto& guid : leakPatternGuids)
	{
		const auto guidString = guid::GUIDToStringAndName(guid);
		WriteOutput(fOut, L"%ws\n", guidString.c_str());
	}

	// Print out leaky prefixes
	WriteOutput(
		fOut,
		L"\nDetected %zu large sets of unique properties sharing a common prefix.\n",
		leakPatternNamePrefixes.size());
	if (!leakPatternNamePrefixes.empty())
	{
		WriteOutput(fOut, L"This typically indicates the incorrect use of named properties by a custom application.\n");
	}

	for (const auto& prefix : leakPatternNamePrefixes)
	{
		WriteOutput(fOut, L"%ws\n", prefix.c_str());
	}
}

/// <summary>
/// Performs the full named property analysis and output.
/// </summary>
/// <param name="lpSession">The MAPI session.</param>
/// <param name="lpMDB">The MAPI message store.</param>
void DoNamedProps(_In_opt_ LPMAPISESSION lpSession, _In_opt_ LPMDB lpMDB)
{
	if (!lpSession || !lpMDB) return;
	registry::cacheNamedProps = false;

	// Ignore the reg key that disables smart view parsing
	registry::doSmartView = true;

	// See if they have specified an output file
	FILE* fOut = nullptr;
	const auto output = cli::switchOutput[0];
	if (!output.empty())
	{
		fOut = output::MyOpenFileMode(output, L"wb");
		if (!fOut)
		{
			wprintf(L"Cannot open output file %ws\n", output.c_str());
			return exit(-1);
		}
	}

	wprintf(L"Dumping named properties...\n\n");

	// Print the name of the profile and the parsed store entry-id so we can tell which mailbox this is
	const auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
	WriteOutput(fOut, L"Timestamp: %hs\n", ctime(&now));
	WriteOutput(fOut, L"Profile Name: %ws\n", mapi::GetProfileName(lpSession).c_str());
	LPSPropValue lpStoreEntryId = nullptr;
	const auto result = WC_H(HrGetOneProp(lpMDB, PR_STORE_ENTRYID, &lpStoreEntryId));
	if (SUCCEEDED(result))
	{
		const auto block = smartview::InterpretBinary(lpStoreEntryId->Value.bin, parserType::ENTRYID, lpMDB);
		const auto storeEntryId = strings::StripCarriage(block->toString());
		WriteOutput(fOut, L"%ws\n\n", storeEntryId.c_str());

		MAPIFreeBuffer(lpStoreEntryId);
	}

	auto names = cache::GetNamesFromIDs(lpMDB, nullptr, 0);

	// Start by analyzing the properties
	AnalyzeNamedProps(fOut, names);

	// Now output all of them
	WriteOutput(fOut, L"\nProperty List:\n");
	std::sort(
		names.begin(),
		names.end(),
		[](std::shared_ptr<cache::namedPropCacheEntry>& i, std::shared_ptr<cache::namedPropCacheEntry>& j) {
			// If the Property set GUIDs don't match, sort by that
			const auto iNameId = i->getMapiNameId();
			const auto jNameId = j->getMapiNameId();
			const auto res = memcmp(iNameId->lpguid, jNameId->lpguid, sizeof(GUID));
			if (res) return res < 0;

			// If they are different kinds, use that next
			if (iNameId->ulKind != jNameId->ulKind)
			{
				return iNameId->ulKind < jNameId->ulKind;
			}

			switch (iNameId->ulKind)
			{
			case MNID_ID:
				return iNameId->Kind.lID < jNameId->Kind.lID;
			case MNID_STRING:
				return std::wstring(iNameId->Kind.lpwstrName) < std::wstring(jNameId->Kind.lpwstrName);
			}

			// This shouldn't ever actually hit
			return i->getPropID() < j->getPropID();
		});

	for (const auto& name : names)
	{
		WriteOutput(fOut, L"[%08X] (", PROP_TAG(PT_UNSPECIFIED, name->getPropID()));
		const auto nameId = name->getMapiNameId();
		PrintGuid(fOut, *nameId->lpguid);
		switch (nameId->ulKind)
		{
		case MNID_ID:
			WriteOutput(fOut, L":0x%04X)\n", nameId->Kind.lID);
			break;

		case MNID_STRING:
			WriteOutput(fOut, L":%ws)\n", nameId->Kind.lpwstrName);
			break;
		}
	}

	wprintf(L"Completed.\n");
	if (fOut) fclose(fOut);
}<|endoftext|>


<commit_before>#ifndef PCL_FEATURES_IMPL_PPFRGB_H_
#define PCL_FEATURES_IMPL_PPFRGB_H_

#include "pcl/features/ppfrgb.h"
#include "pcl/features/pfhrgb.h"

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::PPFRGBEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
  // Slight hack in order to pass the check for the presence of a search method in Feature::initCompute ()
  Feature<PointInT, PointOutT>::tree_.reset (new KdTreeFLANN <PointInT> ());
  Feature<PointInT, PointOutT>::search_radius_ = 1.0f;
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  // Initialize output container - overwrite the sizes done by Feature::initCompute ()
  output.points.resize (indices_->size () * input_->points.size ());
  output.height = 1;
  output.width = output.points.size ();

  // Compute point pair features for every pair of points in the cloud
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    for (size_t j = 0 ; j < input_->points.size (); ++j)
    {
      PointOutT p;
      if (i != j)
      {
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             p.f1, p.f2, p.f3, p.f4, p.r_ratio, p.g_ratio, p.b_ratio))
        {
          // Calculate alpha_m angle
          Eigen::Vector3f model_reference_point = input_->points[i].getVector3fMap (),
              model_reference_normal = normals_->points[i].getNormalVector3fMap (),
              model_point = input_->points[j].getVector3fMap ();
          Eigen::AngleAxisf rotation_mg (acos (model_reference_normal.dot (Eigen::Vector3f::UnitX ())),
                                         model_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ());
          Eigen::Affine3f transform_mg = Eigen::Translation3f ( rotation_mg * ((-1) * model_reference_point)) * rotation_mg;

          Eigen::Vector3f model_point_transformed = transform_mg * model_point;
          float angle = atan2f ( -model_point_transformed(2), model_point_transformed(1));
          if (sin (angle) * model_point_transformed(2) < 0.0f)
            angle *= (-1);
          p.alpha_m = -angle;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
          p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;
        }
      }
      // Do not calculate the feature for identity pairs (i, i) as they are not used
      // in the following computations
      else
        p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;

      output.points[index_i*input_->points.size () + j] = p;
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::PPFRGBRegionEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  PCL_INFO ("before computing output size: %u\n", output.size ());
  output.resize (indices_->size ());
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;
    tree_->radiusSearch (i, search_radius_, nn_indices, nn_distances);

    PointOutT average_feature_nn;
    average_feature_nn.f1 = average_feature_nn.f2 = average_feature_nn.f3 = average_feature_nn.f4 =
        average_feature_nn.r_ratio = average_feature_nn.g_ratio = average_feature_nn.b_ratio = 0.0f;

    for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
    {
      size_t j = *nn_it;
      if (i != j)
      {
        float f1, f2, f3, f4, r_ratio, g_ratio, b_ratio;
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             f1, f2, f3, f4, r_ratio, g_ratio, b_ratio))
        {
          average_feature_nn.f1 += f1;
          average_feature_nn.f2 += f2;
          average_feature_nn.f3 += f3;
          average_feature_nn.f4 += f4;
          average_feature_nn.r_ratio += r_ratio;
          average_feature_nn.g_ratio += g_ratio;
          average_feature_nn.b_ratio += b_ratio;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
        }
      }
    }

    float normalization_factor = nn_indices.size ();
    average_feature_nn.f1 /= normalization_factor;
    average_feature_nn.f2 /= normalization_factor;
    average_feature_nn.f3 /= normalization_factor;
    average_feature_nn.f4 /= normalization_factor;
    average_feature_nn.r_ratio /= normalization_factor;
    average_feature_nn.g_ratio /= normalization_factor;
    average_feature_nn.b_ratio /= normalization_factor;
    output.points[index_i] = average_feature_nn;
  }
  PCL_INFO ("Output size: %u\n", output.points.size ());
}

#define PCL_INSTANTIATE_PPFRGBEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBEstimation<T,NT,OutT>;
#define PCL_INSTANTIATE_PPFRGBRegionEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBRegionEstimation<T,NT,OutT>;

#endif // PCL_FEATURES_IMPL_PPFRGB_H_
<commit_msg>removed a warning for pathcc<commit_after>#ifndef PCL_FEATURES_IMPL_PPFRGB_H_
#define PCL_FEATURES_IMPL_PPFRGB_H_

#include "pcl/features/ppfrgb.h"
#include "pcl/features/pfhrgb.h"

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::PPFRGBEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
  // Slight hack in order to pass the check for the presence of a search method in Feature::initCompute ()
  Feature<PointInT, PointOutT>::tree_.reset (new KdTreeFLANN <PointInT> ());
  Feature<PointInT, PointOutT>::search_radius_ = 1.0f;
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  // Initialize output container - overwrite the sizes done by Feature::initCompute ()
  output.points.resize (indices_->size () * input_->points.size ());
  output.height = 1;
  output.width = output.points.size ();

  // Compute point pair features for every pair of points in the cloud
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    for (size_t j = 0 ; j < input_->points.size (); ++j)
    {
      PointOutT p;
      if (i != j)
      {
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             p.f1, p.f2, p.f3, p.f4, p.r_ratio, p.g_ratio, p.b_ratio))
        {
          // Calculate alpha_m angle
          Eigen::Vector3f model_reference_point = input_->points[i].getVector3fMap (),
              model_reference_normal = normals_->points[i].getNormalVector3fMap (),
              model_point = input_->points[j].getVector3fMap ();
          Eigen::AngleAxisf rotation_mg (acos (model_reference_normal.dot (Eigen::Vector3f::UnitX ())),
                                         model_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ());
          Eigen::Affine3f transform_mg = Eigen::Translation3f ( rotation_mg * ((-1) * model_reference_point)) * rotation_mg;

          Eigen::Vector3f model_point_transformed = transform_mg * model_point;
          float angle = atan2f ( -model_point_transformed(2), model_point_transformed(1));
          if (sin (angle) * model_point_transformed(2) < 0.0f)
            angle *= (-1);
          p.alpha_m = -angle;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
          p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;
        }
      }
      // Do not calculate the feature for identity pairs (i, i) as they are not used
      // in the following computations
      else
        p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;

      output.points[index_i*input_->points.size () + j] = p;
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::PPFRGBRegionEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  PCL_INFO ("before computing output size: %u\n", output.size ());
  output.resize (indices_->size ());
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;
    tree_->radiusSearch (i, search_radius_, nn_indices, nn_distances);

    PointOutT average_feature_nn;
    average_feature_nn.alpha_m = 0;
    average_feature_nn.f1 = average_feature_nn.f2 = average_feature_nn.f3 = average_feature_nn.f4 =
        average_feature_nn.r_ratio = average_feature_nn.g_ratio = average_feature_nn.b_ratio = 0.0f;

    for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
    {
      size_t j = *nn_it;
      if (i != j)
      {
        float f1, f2, f3, f4, r_ratio, g_ratio, b_ratio;
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             f1, f2, f3, f4, r_ratio, g_ratio, b_ratio))
        {
          average_feature_nn.f1 += f1;
          average_feature_nn.f2 += f2;
          average_feature_nn.f3 += f3;
          average_feature_nn.f4 += f4;
          average_feature_nn.r_ratio += r_ratio;
          average_feature_nn.g_ratio += g_ratio;
          average_feature_nn.b_ratio += b_ratio;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
        }
      }
    }

    float normalization_factor = nn_indices.size ();
    average_feature_nn.f1 /= normalization_factor;
    average_feature_nn.f2 /= normalization_factor;
    average_feature_nn.f3 /= normalization_factor;
    average_feature_nn.f4 /= normalization_factor;
    average_feature_nn.r_ratio /= normalization_factor;
    average_feature_nn.g_ratio /= normalization_factor;
    average_feature_nn.b_ratio /= normalization_factor;
    output.points[index_i] = average_feature_nn;
  }
  PCL_INFO ("Output size: %u\n", output.points.size ());
}

#define PCL_INSTANTIATE_PPFRGBEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBEstimation<T,NT,OutT>;
#define PCL_INSTANTIATE_PPFRGBRegionEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBRegionEstimation<T,NT,OutT>;

#endif // PCL_FEATURES_IMPL_PPFRGB_H_
<|endoftext|>


<commit_before><commit_msg>Hard-code modifier key codes since the header file that defines them was not merged.<commit_after><|endoftext|>