<commit_before>#include "vast/configuration.h"
#include "vast/file_system.h"
#include "vast/logger.h"
#include "vast/detail/type_manager.h"
#include "vast/util/color.h"

namespace vast {

std::string configuration::banner() const
{
  std::stringstream ss;
  auto colorize = ! check("log.no-colors");
  if (colorize)
    ss << util::color::red;

  ss << "     _   _____   __________\n"
        "    | | / / _ | / __/_  __/\n"
        "    | |/ / __ |_\\ \\  / /\n"
        "    |___/_/ |_/___/ /_/  ";

  if (colorize)
    ss << util::color::yellow;

  ss << VAST_VERSION;

  if (colorize)
    ss << util::color::reset;

  return ss.str();
}

void configuration::initialize()
{
  auto& general = create_block("general options");
// TODO: not yet supported.
//  general.add('c', "config", "configuration file");
  general.add('h', "help", "display this help");
  general.add('d', "directory", "VAST directory").init("vast");
  general.add('z', "advanced", "show advanced options");
  general.add("version", "print the version of VAST");

  auto min = 0;
  auto max = VAST_LOG_LEVEL;
  auto range = '[' + std::to_string(min) + '-' + std::to_string(max) + ']';

  auto& log = create_block("logger options", "log");
  log.add('v', "console-verbosity", "console verbosity " + range)
     .init(std::min(3, max));
  log.add('V', "file-verbosity", "log file verbosity " + range)
     .init(std::min(4, max));
  log.add("no-colors", "don't use colors for console output");
  log.add("function-names", "log function names");

  auto& advanced = create_block("advanced options");
  advanced.add('P', "profiler", "spawn the profiler ");
  advanced.add("profile-interval", "profiling granularity in seconds").init(1);
#ifdef VAST_USE_PERFTOOLS_CPU_PROFILER
  advanced.add("perftools-cpu", "enable gperftools CPU profiling");
#endif
#ifdef VAST_USE_PERFTOOLS_HEAP_PROFILER
  advanced.add("perftools-heap", "enable gperftools heap profiling");
#endif
  advanced.visible(false);

  auto& act = create_block("actor options");
  act.add('C', "core", "spawn all core actors");
  act.add(/* 'R', */ "receiver", "spawn the receiver");
  act.add(/* 'A', */ "archive", "spawn the archive");
  act.add(/* 'X', */ "index", "spawn the index");
  act.add(/* 'T', */ "tracker", "spawn the tracker");
  act.add(/* 'S', */ "search", "spawn the search");
  act.add('E', "exporter", "spawn the exporter").single();
  act.add('I', "importer", "spawn the importer").single();
#ifdef VAST_HAVE_EDITLINE
  act.add('Q', "console", "spawn the query console");
#endif

  auto& imp = create_block("import options", "import");
  imp.add("batch-size", "number of events to ingest in one run").init(5000);
  imp.add('r', "read", "path to input file/directory").single();
  imp.add('i', "interface", "name of interface to read packets from").single();
  imp.add("pcap-cutoff", "forego intra-flow packets after this many bytes").single();
  imp.add("pcap-maxflows", "number of concurrent flows to track").init(100000);
  imp.visible(false);

  auto& exp = create_block("export options", "export");
  exp.add('l', "limit", "maximum number of results").init(0);
  exp.add('q', "query", "the query string").single();
  exp.add('w', "write", "path to output file/directory").init("-");
  imp.add("pcap-flush", "flush to disk after this many packets").init(10000);
  exp.visible(false);

  auto& recv = create_block("receiver options", "receiver");
  recv.add("host", "hostname/address of the receiver").init("127.0.0.1");
  recv.add("port", "TCP port of the receiver").init(42000);
  recv.visible(false);

  auto& arch = create_block("archive options", "archive");
  arch.add("max-segment-size", "maximum segment size in MB").init(128);
  arch.add("max-segments", "maximum segments cached in memory").init(10);
  arch.add("host", "hostname/address of the archive").init("127.0.0.1");
  arch.add("port", "TCP port of the archive").init(42003);
  arch.visible(false);

  auto& idx = create_block("index options", "index");
  idx.add('p', "partition", "name of the partition to append to").single();
  idx.add("batch-size", "number of events to index in one run").init(1000);
  idx.add("rebuild", "rebuild indexes from archive");
  idx.add("host", "hostname/address of the archive").init("127.0.0.1");
  idx.add("port", "TCP port of the index").init(42004);
  idx.visible(false);

  auto& track = create_block("ID tracker options", "tracker");
  track.add("host", "hostname/address of the tracker").init("127.0.0.1");
  track.add("port", "TCP port of the ID tracker").init(42002);
  track.visible(false);

  auto& srch = create_block("search options", "search");
  srch.add("host", "hostname/address of the archive").init("127.0.0.1");
  srch.add("port", "TCP port of the search").init(42001);
  srch.visible(false);

  add_dependency("profile-interval", "profiler");
#ifdef VAST_USE_PERFTOOLS_CPU_PROFILER
  add_dependency("perftools-cpu", "profiler");
#endif
#ifdef VAST_USE_PERFTOOLS_HEAP_PROFILER
  add_dependency("perftools-heap", "profiler");
#endif

#ifdef VAST_HAVE_EDITLINE
  add_conflict("console", "core");
  add_conflict("console", "tracker");
  add_conflict("console", "archive");
  add_conflict("console", "index");
  add_conflict("console", "importer");
  add_conflict("console", "exporter");
  add_conflict("console", "search");
  add_conflict("console", "receiver");
#endif

  add_dependency("import.format", "importer");
  add_dependency("import.read", "importer");
  add_dependency("import.interface", "importer");
  add_dependency("import.submit", "importer");
  add_dependency("import.pcap-cutoff", "importer");
  add_dependency("import.pcap-maxflows", "importer");
  add_conflict("import.read", "import.interface");

  add_dependency("export.limit", "exporter");
  add_dependency("export.format", "exporter");
  add_dependency("export.query", "exporter");
  add_dependency("export.write", "exporter");
  add_dependency("export.pcap-flush", "exporter");
  add_conflict("importer", "exporter");
  add_conflict("receiver", "exporter");
  add_conflict("tracker", "exporter");

  add_dependencies("index.partition", {"index", "core"});
  add_conflict("index.rebuild", "index.partition");

}

} // namespace vast
<commit_msg>Increase max concurrent flows to 1M.<commit_after>#include "vast/configuration.h"
#include "vast/file_system.h"
#include "vast/logger.h"
#include "vast/detail/type_manager.h"
#include "vast/util/color.h"

namespace vast {

std::string configuration::banner() const
{
  std::stringstream ss;
  auto colorize = ! check("log.no-colors");
  if (colorize)
    ss << util::color::red;

  ss << "     _   _____   __________\n"
        "    | | / / _ | / __/_  __/\n"
        "    | |/ / __ |_\\ \\  / /\n"
        "    |___/_/ |_/___/ /_/  ";

  if (colorize)
    ss << util::color::yellow;

  ss << VAST_VERSION;

  if (colorize)
    ss << util::color::reset;

  return ss.str();
}

void configuration::initialize()
{
  auto& general = create_block("general options");
// TODO: not yet supported.
//  general.add('c', "config", "configuration file");
  general.add('h', "help", "display this help");
  general.add('d', "directory", "VAST directory").init("vast");
  general.add('z', "advanced", "show advanced options");
  general.add("version", "print the version of VAST");

  auto min = 0;
  auto max = VAST_LOG_LEVEL;
  auto range = '[' + std::to_string(min) + '-' + std::to_string(max) + ']';

  auto& log = create_block("logger options", "log");
  log.add('v', "console-verbosity", "console verbosity " + range)
     .init(std::min(3, max));
  log.add('V', "file-verbosity", "log file verbosity " + range)
     .init(std::min(4, max));
  log.add("no-colors", "don't use colors for console output");
  log.add("function-names", "log function names");

  auto& advanced = create_block("advanced options");
  advanced.add('P', "profiler", "spawn the profiler ");
  advanced.add("profile-interval", "profiling granularity in seconds").init(1);
#ifdef VAST_USE_PERFTOOLS_CPU_PROFILER
  advanced.add("perftools-cpu", "enable gperftools CPU profiling");
#endif
#ifdef VAST_USE_PERFTOOLS_HEAP_PROFILER
  advanced.add("perftools-heap", "enable gperftools heap profiling");
#endif
  advanced.visible(false);

  auto& act = create_block("actor options");
  act.add('C', "core", "spawn all core actors");
  act.add(/* 'R', */ "receiver", "spawn the receiver");
  act.add(/* 'A', */ "archive", "spawn the archive");
  act.add(/* 'X', */ "index", "spawn the index");
  act.add(/* 'T', */ "tracker", "spawn the tracker");
  act.add(/* 'S', */ "search", "spawn the search");
  act.add('E', "exporter", "spawn the exporter").single();
  act.add('I', "importer", "spawn the importer").single();
#ifdef VAST_HAVE_EDITLINE
  act.add('Q', "console", "spawn the query console");
#endif

  auto& imp = create_block("import options", "import");
  imp.add("batch-size", "number of events to ingest in one run").init(5000);
  imp.add('r', "read", "path to input file/directory").single();
  imp.add('i', "interface", "name of interface to read packets from").single();
  imp.add("pcap-cutoff", "forego intra-flow packets after this many bytes").single();
  imp.add("pcap-maxflows", "number of concurrent flows to track").init(1000000);
  imp.visible(false);

  auto& exp = create_block("export options", "export");
  exp.add('l', "limit", "maximum number of results").init(0);
  exp.add('q', "query", "the query string").single();
  exp.add('w', "write", "path to output file/directory").init("-");
  imp.add("pcap-flush", "flush to disk after this many packets").init(10000);
  exp.visible(false);

  auto& recv = create_block("receiver options", "receiver");
  recv.add("host", "hostname/address of the receiver").init("127.0.0.1");
  recv.add("port", "TCP port of the receiver").init(42000);
  recv.visible(false);

  auto& arch = create_block("archive options", "archive");
  arch.add("max-segment-size", "maximum segment size in MB").init(128);
  arch.add("max-segments", "maximum segments cached in memory").init(10);
  arch.add("host", "hostname/address of the archive").init("127.0.0.1");
  arch.add("port", "TCP port of the archive").init(42003);
  arch.visible(false);

  auto& idx = create_block("index options", "index");
  idx.add('p', "partition", "name of the partition to append to").single();
  idx.add("batch-size", "number of events to index in one run").init(1000);
  idx.add("rebuild", "rebuild indexes from archive");
  idx.add("host", "hostname/address of the archive").init("127.0.0.1");
  idx.add("port", "TCP port of the index").init(42004);
  idx.visible(false);

  auto& track = create_block("ID tracker options", "tracker");
  track.add("host", "hostname/address of the tracker").init("127.0.0.1");
  track.add("port", "TCP port of the ID tracker").init(42002);
  track.visible(false);

  auto& srch = create_block("search options", "search");
  srch.add("host", "hostname/address of the archive").init("127.0.0.1");
  srch.add("port", "TCP port of the search").init(42001);
  srch.visible(false);

  add_dependency("profile-interval", "profiler");
#ifdef VAST_USE_PERFTOOLS_CPU_PROFILER
  add_dependency("perftools-cpu", "profiler");
#endif
#ifdef VAST_USE_PERFTOOLS_HEAP_PROFILER
  add_dependency("perftools-heap", "profiler");
#endif

#ifdef VAST_HAVE_EDITLINE
  add_conflict("console", "core");
  add_conflict("console", "tracker");
  add_conflict("console", "archive");
  add_conflict("console", "index");
  add_conflict("console", "importer");
  add_conflict("console", "exporter");
  add_conflict("console", "search");
  add_conflict("console", "receiver");
#endif

  add_dependency("import.format", "importer");
  add_dependency("import.read", "importer");
  add_dependency("import.interface", "importer");
  add_dependency("import.submit", "importer");
  add_dependency("import.pcap-cutoff", "importer");
  add_dependency("import.pcap-maxflows", "importer");
  add_conflict("import.read", "import.interface");

  add_dependency("export.limit", "exporter");
  add_dependency("export.format", "exporter");
  add_dependency("export.query", "exporter");
  add_dependency("export.write", "exporter");
  add_dependency("export.pcap-flush", "exporter");
  add_conflict("importer", "exporter");
  add_conflict("receiver", "exporter");
  add_conflict("tracker", "exporter");

  add_dependencies("index.partition", {"index", "core"});
  add_conflict("index.rebuild", "index.partition");

}

} // namespace vast
<|endoftext|>


<commit_before>#include <assert.h>
#include "ScheduleActualizer.h"
#include "Extensions/ScheduleActualizationAlgorithm.h"

namespace Scheduler
{

    ScheduleActualizer::ScheduleActualizer(Schedule *schedule):
    schedule(schedule),
    algorithms_factory(nullptr),
	is_actualizing(false)
    {
    }

	ScheduleActualizer::ScheduleActualizer(Schedule * schedule, const ScheduleActualizer & rhs):
		schedule(schedule),
		algorithms_factory(rhs.algorithms_factory)
	{
		for (ScheduleActualizationAlgorithm* algorithm : rhs.algorithms)
		{
			algorithms.push_back(algorithm->clone(schedule, algorithms_factory));
		}
	}

    void ScheduleActualizer::onOperationAdded(const Stop *stop, const Operation *operation) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onOperationAdded(stop, operation);
    }

    void ScheduleActualizer::onOperationRemoved(const Stop *stop) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onOperationRemoved(stop);
    }

    void ScheduleActualizer::onStopAdded(const Run *run, const Stop *stop, size_t index) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopAdded(run, stop, index);
    }

    void ScheduleActualizer::onStopRemoved(const Run *run, size_t index) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopRemoved(run, index);
    }

	void ScheduleActualizer::onStopReplaced(const Run * run, const Stop * new_stop, size_t index)
	{
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopReplaced(run, new_stop, index);
	}

    void ScheduleActualizer::onRunVehicleChanged(const Run *run, const Vehicle *vehicle) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onRunVehicleChanged(run, vehicle);
    }

    void ScheduleActualizer::onRunAdded(const Run *run, size_t index) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onRunAdded(run, index);
    }

    void ScheduleActualizer::onRunRemoved() {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onRunRemoved();
    }

    void ScheduleActualizer::actualize() {
		if(is_actualizing) return;
		is_actualizing = true;
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->actualize();
		is_actualizing = false;
    }

    ScheduleActualizer::~ScheduleActualizer() {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithms_factory->destroyObject(algorithm);
    }

    void ScheduleActualizer::onStopNextRouteChanged(const Stop *stop) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopNextRouteChanged(stop);
    }

    void ScheduleActualizer::setScheduleActualizationAlgorithmsFactory(
            Factory<ScheduleActualizationAlgorithm> *factory) {
        this->algorithms_factory = factory;
    }
}<commit_msg>[#65] Fixed copy constructor of ScheduleActualizer<commit_after>#include <assert.h>
#include "ScheduleActualizer.h"
#include "Extensions/ScheduleActualizationAlgorithm.h"

namespace Scheduler
{

    ScheduleActualizer::ScheduleActualizer(Schedule *schedule):
    schedule(schedule),
    algorithms_factory(nullptr),
	is_actualizing(false)
    {
    }

	ScheduleActualizer::ScheduleActualizer(Schedule * schedule, const ScheduleActualizer & rhs):
		schedule(schedule),
		algorithms_factory(rhs.algorithms_factory),
		is_actualizing(false)
	{
		for (ScheduleActualizationAlgorithm* algorithm : rhs.algorithms)
		{
			algorithms.push_back(algorithm->clone(schedule, algorithms_factory));
		}
	}

    void ScheduleActualizer::onOperationAdded(const Stop *stop, const Operation *operation) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onOperationAdded(stop, operation);
    }

    void ScheduleActualizer::onOperationRemoved(const Stop *stop) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onOperationRemoved(stop);
    }

    void ScheduleActualizer::onStopAdded(const Run *run, const Stop *stop, size_t index) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopAdded(run, stop, index);
    }

    void ScheduleActualizer::onStopRemoved(const Run *run, size_t index) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopRemoved(run, index);
    }

	void ScheduleActualizer::onStopReplaced(const Run * run, const Stop * new_stop, size_t index)
	{
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopReplaced(run, new_stop, index);
	}

    void ScheduleActualizer::onRunVehicleChanged(const Run *run, const Vehicle *vehicle) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onRunVehicleChanged(run, vehicle);
    }

    void ScheduleActualizer::onRunAdded(const Run *run, size_t index) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onRunAdded(run, index);
    }

    void ScheduleActualizer::onRunRemoved() {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onRunRemoved();
    }

    void ScheduleActualizer::actualize() {
		if(is_actualizing) return;
		is_actualizing = true;
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->actualize();
		is_actualizing = false;
    }

    ScheduleActualizer::~ScheduleActualizer() {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithms_factory->destroyObject(algorithm);
    }

    void ScheduleActualizer::onStopNextRouteChanged(const Stop *stop) {
        for(ScheduleActualizationAlgorithm* algorithm : algorithms) algorithm->onStopNextRouteChanged(stop);
    }

    void ScheduleActualizer::setScheduleActualizationAlgorithmsFactory(
            Factory<ScheduleActualizationAlgorithm> *factory) {
        this->algorithms_factory = factory;
    }
}<|endoftext|>


<commit_before>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

                Copyright (c) 2003-2019, Cauldron Development LLC
                   Copyright (c) 2003-2017, Stanford University
                               All rights reserved.

         The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
       as published by the Free Software Foundation, either version 2.1 of
               the License, or (at your option) any later version.

        The C! library is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                 Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
                 License along with the C! library.  If not, see
                         <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
           You may request written permission by emailing the authors.

                  For information regarding this software email:
                                 Joseph Coffland
                          joseph@cauldrondevelopment.com

\******************************************************************************/

#include "Base64.h"

#include <cbang/Exception.h>

#include <locale>

using namespace std;
using namespace cb;

const char *Base64::encodeTable =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

const signed char Base64::decodeTable[256] = {
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
  -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};

string Base64::encode(const string &s) const {
  return encode(s.c_str(), s.length());
}

string Base64::encode(const char *_s, unsigned length) const {
  const uint8_t *s = (uint8_t *)_s;
  const uint8_t *end = s + length;
  string result;
  unsigned size = length / 3 * 4 + 4; // Not exact
  if (width) size += (size / width) * 2;
  result.reserve(size);

  unsigned col = 0;
  int padding = 0;
  uint8_t a, b, c;
  while (s != end) {
    a = *s++;
    if (s == end) {c = b = 0; padding = 2;}
    else {
      b = *s++;
      if (s == end) {c = 0; padding = 1;}
      else c = *s++;
    }

    result += encode(63 & (a >> 2));
    result += encode(63 & (a << 4 | b >> 4));
    if (pad && padding == 2) result += pad;
    else result += encode(63 & (b << 2 | c >> 6));
    if (pad && padding) result += pad;
    else result += encode(63 & c);

    if (s != end && width) {
      col += 4;
      if (col == width) {
        col = 0;
        result += "\r\n";
      }
    }
  }

  return result;
}

string Base64::decode(const string &s) const {
  string result;
  result.reserve(s.length() / 4 * 3 + 1);

  string::const_iterator it = s.begin();
  while (it != s.end() && isspace(*it)) it++;

  while (it != s.end()) {
    char w = decode(next(it, s.end()));
    char x = it == s.end() ? -2 : decode(next(it, s.end()));
    char y = it == s.end() ? -2 : decode(next(it, s.end()));
    char z = it == s.end() ? -2 : decode(next(it, s.end()));

    if (w == -2 || x == -2 || w == -1 || x == -1 || y == -1 || z == -1)
      THROW("Invalid Base64 data at " << (it - s.begin()));

    result += (char)(w << 2 | x >> 4);
    if (y != -2) {
      result += (char)(x << 4 | y >> 2);
      if (z != -2) result += (char)(y << 6 | z);
    }
  }

  return result;
}

char Base64::next(string::const_iterator &it,
                  string::const_iterator end) {
  char c = *it++;
  while (it != end && isspace(*it)) it++;
  return c;
}

char Base64::encode(int x) const {
  if (x == 62) return a;
  if (x == 63) return b;
  return encodeTable[x];
}

int Base64::decode(char x) const {
  if (x == a) return 62;
  if (x == b) return 63;
  if (x == pad) return -2;
  return decodeTable[(int)x];
}
<commit_msg>Fixed Base64 w/ no padding<commit_after>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

                Copyright (c) 2003-2019, Cauldron Development LLC
                   Copyright (c) 2003-2017, Stanford University
                               All rights reserved.

         The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
       as published by the Free Software Foundation, either version 2.1 of
               the License, or (at your option) any later version.

        The C! library is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                 Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
                 License along with the C! library.  If not, see
                         <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
           You may request written permission by emailing the authors.

                  For information regarding this software email:
                                 Joseph Coffland
                          joseph@cauldrondevelopment.com

\******************************************************************************/

#include "Base64.h"

#include <cbang/Exception.h>

#include <locale>

using namespace std;
using namespace cb;

const char *Base64::encodeTable =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

const signed char Base64::decodeTable[256] = {
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
  -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};

string Base64::encode(const string &s) const {
  return encode(s.c_str(), s.length());
}

string Base64::encode(const char *_s, unsigned length) const {
  const uint8_t *s = (uint8_t *)_s;
  const uint8_t *end = s + length;
  string result;
  unsigned size = length / 3 * 4 + 4; // Not exact
  if (width) size += (size / width) * 2;
  result.reserve(size);

  unsigned col = 0;
  int padding = 0;
  uint8_t a, b, c;
  while (s != end) {
    a = *s++;
    if (s == end) {c = b = 0; padding = 2;}
    else {
      b = *s++;
      if (s == end) {c = 0; padding = 1;}
      else c = *s++;
    }

    result += encode(63 & (a >> 2));
    result += encode(63 & (a << 4 | b >> 4));
    if (padding == 2) {if (pad) result += pad;}
    else result += encode(63 & (b << 2 | c >> 6));
    if (padding) {if (pad) result += pad;}
    else result += encode(63 & c);

    if (s != end && width) {
      col += 4;
      if (col == width) {
        col = 0;
        result += "\r\n";
      }
    }
  }

  return result;
}

string Base64::decode(const string &s) const {
  string result;
  result.reserve(s.length() / 4 * 3 + 1);

  string::const_iterator it = s.begin();
  while (it != s.end() && isspace(*it)) it++;

  while (it != s.end()) {
    char w = decode(next(it, s.end()));
    char x = it == s.end() ? -2 : decode(next(it, s.end()));
    char y = it == s.end() ? -2 : decode(next(it, s.end()));
    char z = it == s.end() ? -2 : decode(next(it, s.end()));

    if (w == -2 || x == -2 || w == -1 || x == -1 || y == -1 || z == -1)
      THROW("Invalid Base64 data at " << (it - s.begin()));

    result += (char)(w << 2 | x >> 4);
    if (y != -2) {
      result += (char)(x << 4 | y >> 2);
      if (z != -2) result += (char)(y << 6 | z);
    }
  }

  return result;
}

char Base64::next(string::const_iterator &it,
                  string::const_iterator end) {
  char c = *it++;
  while (it != end && isspace(*it)) it++;
  return c;
}

char Base64::encode(int x) const {
  if (x == 62) return a;
  if (x == 63) return b;
  return encodeTable[x];
}

int Base64::decode(char x) const {
  if (x == a) return 62;
  if (x == b) return 63;
  if (x == pad) return -2;
  return decodeTable[(int)x];
}
<|endoftext|>


<commit_before>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

                Copyright (c) 2003-2019, Cauldron Development LLC
                   Copyright (c) 2003-2017, Stanford University
                               All rights reserved.

         The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
       as published by the Free Software Foundation, either version 2.1 of
               the License, or (at your option) any later version.

        The C! library is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                 Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
                 License along with the C! library.  If not, see
                         <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
           You may request written permission by emailing the authors.

                  For information regarding this software email:
                                 Joseph Coffland
                          joseph@cauldrondevelopment.com

\******************************************************************************/

#include "Base64.h"

#include <cbang/Exception.h>

#include <locale>

using namespace std;
using namespace cb;

namespace {
  char next(string::const_iterator &it, string::const_iterator end) {
    char c = *it++;
    while (it != end && isspace(*it)) it++;
    return c;
  }
}

const char *Base64::encodeTable =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

const signed char Base64::decodeTable[256] = {
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
  -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};

string Base64::encode(const string &s) const {
  return encode(s.c_str(), s.length());
}

string Base64::encode(const char *_s, unsigned length) const {
  const uint8_t *s = (uint8_t *)_s;
  const uint8_t *end = s + length;

  struct Result : public string {
    unsigned col = 0;
    unsigned width;

    Result(unsigned length, unsigned width) : width(width) {
      unsigned size = length / 3 * 4 + 4; // Not exact
      if (width) size += (size / width) * 2;
      reserve(size);
    }

    void append(char c) {
      if (width) {
        if (col == width) {
          col = 0;
          string::append("\r\n");

        } else col++;
      }

      string::append(1, c);
    }
  };

  Result result(length, width);
  int padding = 0;
  uint8_t a, b, c;

  while (s != end) {
    a = *s++;
    if (s == end) {c = b = 0; padding = 2;}
    else {
      b = *s++;
      if (s == end) {c = 0; padding = 1;}
      else c = *s++;
    }

    result.append(encode(63 & (a >> 2)));
    result.append(encode(63 & (a << 4 | b >> 4)));
    if (padding == 2) {if (pad) result.append(pad);}
    else result.append(encode(63 & (b << 2 | c >> 6)));
    if (padding) {if (pad) result.append(pad);}
    else result.append(encode(63 & c));
  }

  return result;
}

string Base64::decode(const string &s) const {
  string result;
  result.reserve(s.length() / 4 * 3 + 1);

  string::const_iterator it = s.begin();
  while (it != s.end() && isspace(*it)) it++;

  while (it != s.end()) {
    char w = decode(next(it, s.end()));
    char x = it == s.end() ? -2 : decode(next(it, s.end()));
    char y = it == s.end() ? -2 : decode(next(it, s.end()));
    char z = it == s.end() ? -2 : decode(next(it, s.end()));

    if (w == -1 || w == -2 || x == -1 || x == -2 || y == -1 || z == -1)
      THROW("Invalid Base64 data at " << (it - s.begin()));

    result += (char)(w << 2 | x >> 4);
    if (y != -2) {
      result += (char)(x << 4 | y >> 2);
      if (z != -2) result += (char)(y << 6 | z);
    }
  }

  return result;
}

string Base64::decode(const char *s, unsigned length) const {
  return decode(string(s, length));
}

char Base64::encode(int x) const {
  if (x == 62) return a;
  if (x == 63) return b;
  return encodeTable[x];
}

int Base64::decode(char x) const {
  if (x == a) return 62;
  if (x == b) return 63;
  if (x == pad) return -2;
  return decodeTable[(int)x];
}
<commit_msg>Move result<commit_after>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

                Copyright (c) 2003-2019, Cauldron Development LLC
                   Copyright (c) 2003-2017, Stanford University
                               All rights reserved.

         The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
       as published by the Free Software Foundation, either version 2.1 of
               the License, or (at your option) any later version.

        The C! library is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                 Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
                 License along with the C! library.  If not, see
                         <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
           You may request written permission by emailing the authors.

                  For information regarding this software email:
                                 Joseph Coffland
                          joseph@cauldrondevelopment.com

\******************************************************************************/

#include "Base64.h"

#include <cbang/Exception.h>

#include <locale>
#include <utility> // std::move()

using namespace std;
using namespace cb;

namespace {
  char next(string::const_iterator &it, string::const_iterator end) {
    char c = *it++;
    while (it != end && isspace(*it)) it++;
    return c;
  }
}

const char *Base64::encodeTable =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

const signed char Base64::decodeTable[256] = {
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
  -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};

string Base64::encode(const string &s) const {
  return encode(s.c_str(), s.length());
}

string Base64::encode(const char *_s, unsigned length) const {
  const uint8_t *s = (uint8_t *)_s;
  const uint8_t *end = s + length;

  struct Result : public string {
    unsigned col = 0;
    unsigned width;

    Result(unsigned length, unsigned width) : width(width) {
      unsigned size = length / 3 * 4 + 4; // Not exact
      if (width) size += (size / width) * 2;
      reserve(size);
    }

    void append(char c) {
      if (width) {
        if (col == width) {
          col = 0;
          string::append("\r\n");

        } else col++;
      }

      string::append(1, c);
    }
  };

  Result result(length, width);
  int padding = 0;
  uint8_t a, b, c;

  while (s != end) {
    a = *s++;
    if (s == end) {c = b = 0; padding = 2;}
    else {
      b = *s++;
      if (s == end) {c = 0; padding = 1;}
      else c = *s++;
    }

    result.append(encode(63 & (a >> 2)));
    result.append(encode(63 & (a << 4 | b >> 4)));
    if (padding == 2) {if (pad) result.append(pad);}
    else result.append(encode(63 & (b << 2 | c >> 6)));
    if (padding) {if (pad) result.append(pad);}
    else result.append(encode(63 & c));
  }

  return move(result);
}

string Base64::decode(const string &s) const {
  string result;
  result.reserve(s.length() / 4 * 3 + 1);

  string::const_iterator it = s.begin();
  while (it != s.end() && isspace(*it)) it++;

  while (it != s.end()) {
    char w = decode(next(it, s.end()));
    char x = it == s.end() ? -2 : decode(next(it, s.end()));
    char y = it == s.end() ? -2 : decode(next(it, s.end()));
    char z = it == s.end() ? -2 : decode(next(it, s.end()));

    if (w == -1 || w == -2 || x == -1 || x == -2 || y == -1 || z == -1)
      THROW("Invalid Base64 data at " << (it - s.begin()));

    result += (char)(w << 2 | x >> 4);
    if (y != -2) {
      result += (char)(x << 4 | y >> 2);
      if (z != -2) result += (char)(y << 6 | z);
    }
  }

  return result;
}

string Base64::decode(const char *s, unsigned length) const {
  return decode(string(s, length));
}

char Base64::encode(int x) const {
  if (x == 62) return a;
  if (x == 63) return b;
  return encodeTable[x];
}

int Base64::decode(char x) const {
  if (x == a) return 62;
  if (x == b) return 63;
  if (x == pad) return -2;
  return decodeTable[(int)x];
}
<|endoftext|>


<commit_before>// main.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Utilities.h"

// Functions to load in a single image or all images
Mat loadImage(char* location, char* file);
Mat* loadImages(int numberOfImages, char* location, char** files);

// A function which temporarily resizes images before showing them
void showImage(char* name, Mat image);

// "Sign" functions - used to detect bus stop signs
Mat findSign(Mat image);
Mat binaryImage(Mat image);
Mat backProjection(Mat image, Mat yellow);
Mat getHue(Mat image);
Mat templateMatching(Mat image, Mat templateImage);

// "Number" function - used to detect the stop number from the sign
int digitRecognition(Mat image);

int _tmain(int argc, _TCHAR* argv[])
{
	cout << "Using OpenCV " << CV_VERSION << endl;
	char* testLocation = "Media/Test Images/";	// Location of bus stop sign images

	// Bus stop sign images
	char* testFiles[] = {
		"2809 a.jpg",
		"2809 b.jpg",
		"2830 a.jpg",
		"2830 b.jpg",
		"2838 a.jpg",
		"2838 b.jpg",
		"2838 c.jpg",
		"2838 d.jpg",
		"2839 a.jpg",
		"2839 b.jpg",
		"2839 c.jpg",
		"2839 d.jpg"
	};

	char* templateLocation = "Media/Templates/";	// Location of sample stop sign images

	// Sample stop sign images
	char* templateFiles[] = {
		"stop.png",
		"stop&no.png",
		"stop2.png",
		"stop&no2.png",
		"yellow.png"
	};

	Mat sign = loadImage(testLocation, testFiles[6]);
	Mat templateSign = loadImage(templateLocation, templateFiles[2]);
	Mat yellow = loadImage(templateLocation, templateFiles[4]);

	showImage("Bus Stop Sign", sign);
	Mat hsvSign = findSign(sign);
	Mat binary = binaryImage(sign);
	Mat backProjSign = backProjection(sign, yellow);
	//Mat templateMatch = templateMatching(sign, templateSign);
	Mat templateMatch = templateMatching(sign, yellow);

	showImage("HSV", hsvSign);
	showImage("Binary", binary);
	showImage("Back Projection", backProjSign);
	showImage("Template Matching", templateMatch);
	waitKey(0);

	int stopNumber = digitRecognition(backProjSign);

	/*int numberOfTestImages = sizeof(testFiles) / sizeof(testFiles[0]);
	Mat* busStops = loadImages(numberOfTestImages, testLocation, testFiles);
	int numberOfTemplateImages = sizeof(templateFiles) / sizeof(templateFiles[0]);
	Mat* templates = loadImages(numberOfTemplateImages, templateLocation, templateFiles);

	for (int i = 0; i < numberOfTestImages; i++) {
		cout << "Processing image " << (i + 1) << endl;
		showImage("Sign", busStops[i]);
		Mat hsvSign = findSign(busStops[i]);
		Mat binary = binaryImage(busStops[i]);
		Mat backProjSign = backProjection(busStops[i], templates[4]);
		Mat templateMatch;
		if (i == 0 || i == 1) {
			// templates[0] or templates[1]
			templateMatch = templateMatching(busStops[i], templates[0]);

		}
		else {
			// templates[2] or templates[3]
			templateMatch = templateMatching(busStops[i], templates[2]);

		}

		showImage("HSV", hsvSign);
		showImage("Binary", binary);
		showImage("Back Projection", backProjSign);
		showImage("Template Matching", templateMatch);

		waitKey(0);
	}*/

	return 0;
}

Mat loadImage(char* location, char* file) {
	string filename(location);
	filename.append(file);
	Mat image = imread(filename, 1);

	return image;
}

Mat* loadImages(int numberOfImages, char* location, char** files) {
	Mat* images = new Mat[numberOfImages];
	for (int i = 0; i < numberOfImages; i++) {
		string filename(location);
		filename.append(files[i]);
		cout << "Loading image " << (i + 1) << ": " << filename << endl;
		images[i] = imread(filename, 1);
	}
	return images;
}

void showImage(char* name, Mat image) {
	resize(image, image, Size(image.cols / 4, image.rows / 4));
	imshow(name, image);

	return;
}

Mat findSign(Mat image) {
	Mat hsv;
	cvtColor(image, hsv, CV_BGR2HSV);
	inRange(hsv, Scalar(15, 135, 140), Scalar(30, 255, 255), hsv);

	return hsv;
}

Mat binaryImage(Mat image) {
	Mat greyImage, binaryResult;
	cvtColor(image, greyImage, CV_BGR2GRAY);
	threshold(greyImage, binaryResult, 200, 255, THRESH_BINARY);

	return binaryResult;
}

Mat backProjection(Mat image, Mat yellow) {
	Mat imageHue = getHue(image);
	Mat yellowHue = getHue(yellow);

	Mat hist;
	int histSize = 180;
	float hue_range[] = { 0, 180 };
	const float* ranges = { hue_range };

	calcHist(&yellowHue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);
	normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());

	Mat backProject;
	calcBackProject(&imageHue, 1, 0, hist, backProject, &ranges, 1, true);

	return backProject;
}

Mat getHue(Mat image) {
	Mat hsv, hue;
	cvtColor(image, hsv, CV_BGR2HSV);

	hue.create(hsv.size(), hsv.depth());
	int ch[] = { 0, 0 };
	mixChannels(&hsv, 1, &hue, 1, ch, 1);

	return hue;
}

Mat templateMatching(Mat image, Mat templateImage) {
	Mat result;

	Mat imageDisplay;
	image.copyTo(imageDisplay);

	int rows = image.rows - templateImage.rows + 1;
	int cols = image.cols - templateImage.cols + 1;

	result.create(rows, cols, CV_32FC1);

	matchTemplate(image, templateImage, result, CV_TM_SQDIFF);
	normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

	double minVal, maxVal;
	Point minLoc, maxLoc, matchLoc;

	minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());

	matchLoc = minLoc;

	rectangle(imageDisplay, matchLoc, Point(matchLoc.x + templateImage.cols, matchLoc.y + templateImage.rows), Scalar::all(0), 2, 8, 0);
	rectangle(result, matchLoc, Point(matchLoc.x + templateImage.cols, matchLoc.y + templateImage.rows), Scalar::all(0), 2, 8, 0);

	/*showImage("Image", imageDisplay);
	showImage("Result", result);
	waitKey(0);*/

	//return result;
	return imageDisplay;
}

int digitRecognition(Mat image) {
	// TODO: recognise numbers from sign
	// Statistical Pattern Recognition
	// Scene Text Recognition - OCRTesseract
	// Template Matching
	// Chamfer Matching
	// Haar Classifiers

	return 0;
}<commit_msg>renamed variable<commit_after>// main.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Utilities.h"

// Functions to load in a single image or all images
Mat loadImage(char* location, char* file);
Mat* loadImages(int numberOfImages, char* location, char** files);

// A function which temporarily resizes images before showing them
void showImage(char* name, Mat image);

// "Sign" functions - used to detect bus stop signs
Mat findSign(Mat image);
Mat binaryImage(Mat image);
Mat backProjection(Mat image, Mat yellow);
Mat getHue(Mat image);
Mat templateMatching(Mat image, Mat templateImage);

// "Number" function - used to detect the stop number from the sign
int digitRecognition(Mat image);

int _tmain(int argc, _TCHAR* argv[])
{
	cout << "Using OpenCV " << CV_VERSION << endl;
	char* testLocation = "Media/Test Images/";	// Location of bus stop sign images

	// Bus stop sign images
	char* testFiles[] = {
		"2809 a.jpg",
		"2809 b.jpg",
		"2830 a.jpg",
		"2830 b.jpg",
		"2838 a.jpg",
		"2838 b.jpg",
		"2838 c.jpg",
		"2838 d.jpg",
		"2839 a.jpg",
		"2839 b.jpg",
		"2839 c.jpg",
		"2839 d.jpg"
	};

	char* templateLocation = "Media/Templates/";	// Location of sample stop sign images

	// Sample stop sign images
	char* templateFiles[] = {
		"stop.png",
		"stop&no.png",
		"stop2.png",
		"stop&no2.png",
		"yellow.png"
	};

	Mat sign = loadImage(testLocation, testFiles[6]);
	Mat templateSign = loadImage(templateLocation, templateFiles[2]);
	Mat yellow = loadImage(templateLocation, templateFiles[4]);

	showImage("Bus Stop Sign", sign);
	Mat hsvSign = findSign(sign);
	Mat binary = binaryImage(sign);
	Mat backProjSign = backProjection(sign, yellow);
	//Mat templateMatch = templateMatching(sign, templateSign);
	Mat templateMatch = templateMatching(sign, yellow);

	showImage("HSV", hsvSign);
	showImage("Binary", binary);
	showImage("Back Projection", backProjSign);
	showImage("Template Matching", templateMatch);
	waitKey(0);

	int stopNumber = digitRecognition(backProjSign);

	/*int numberOfTestImages = sizeof(testFiles) / sizeof(testFiles[0]);
	Mat* busStops = loadImages(numberOfTestImages, testLocation, testFiles);
	int numberOfTemplateImages = sizeof(templateFiles) / sizeof(templateFiles[0]);
	Mat* templates = loadImages(numberOfTemplateImages, templateLocation, templateFiles);

	for (int i = 0; i < numberOfTestImages; i++) {
		cout << "Processing image " << (i + 1) << endl;
		showImage("Sign", busStops[i]);
		Mat hsvSign = findSign(busStops[i]);
		Mat binary = binaryImage(busStops[i]);
		Mat backProjSign = backProjection(busStops[i], templates[4]);
		Mat templateMatch;
		if (i == 0 || i == 1) {
			// templates[0] or templates[1]
			templateMatch = templateMatching(busStops[i], templates[0]);

		}
		else {
			// templates[2] or templates[3]
			templateMatch = templateMatching(busStops[i], templates[2]);

		}

		showImage("HSV", hsvSign);
		showImage("Binary", binary);
		showImage("Back Projection", backProjSign);
		showImage("Template Matching", templateMatch);

		waitKey(0);
	}*/

	return 0;
}

Mat loadImage(char* location, char* file) {
	string filename(location);
	filename.append(file);
	Mat image = imread(filename, 1);

	return image;
}

Mat* loadImages(int numberOfImages, char* location, char** files) {
	Mat* images = new Mat[numberOfImages];
	for (int i = 0; i < numberOfImages; i++) {
		string filename(location);
		filename.append(files[i]);
		cout << "Loading image " << (i + 1) << ": " << filename << endl;
		images[i] = imread(filename, 1);
	}
	return images;
}

void showImage(char* name, Mat image) {
	resize(image, image, Size(image.cols / 4, image.rows / 4));
	imshow(name, image);

	return;
}

Mat findSign(Mat image) {
	Mat hsv;
	cvtColor(image, hsv, CV_BGR2HSV);
	inRange(hsv, Scalar(15, 135, 140), Scalar(30, 255, 255), hsv);

	return hsv;
}

Mat binaryImage(Mat image) {
	Mat greyImage, binaryResult;
	cvtColor(image, greyImage, CV_BGR2GRAY);
	threshold(greyImage, binaryResult, 200, 255, THRESH_BINARY);

	return binaryResult;
}

Mat backProjection(Mat image, Mat yellow) {
	Mat imageHue = getHue(image);
	Mat yellowHue = getHue(yellow);

	Mat hist;
	int histSize = 180;
	float hueRange[] = { 0, 180 };
	const float* ranges = { hueRange };

	calcHist(&yellowHue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);
	normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());

	Mat backProject;
	calcBackProject(&imageHue, 1, 0, hist, backProject, &ranges, 1, true);

	return backProject;
}

Mat getHue(Mat image) {
	Mat hsv, hue;
	cvtColor(image, hsv, CV_BGR2HSV);

	hue.create(hsv.size(), hsv.depth());
	int ch[] = { 0, 0 };
	mixChannels(&hsv, 1, &hue, 1, ch, 1);

	return hue;
}

Mat templateMatching(Mat image, Mat templateImage) {
	Mat result;

	Mat imageDisplay;
	image.copyTo(imageDisplay);

	int rows = image.rows - templateImage.rows + 1;
	int cols = image.cols - templateImage.cols + 1;

	result.create(rows, cols, CV_32FC1);

	matchTemplate(image, templateImage, result, CV_TM_SQDIFF);
	normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());

	double minVal, maxVal;
	Point minLoc, maxLoc, matchLoc;

	minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc, Mat());

	matchLoc = minLoc;

	rectangle(imageDisplay, matchLoc, Point(matchLoc.x + templateImage.cols, matchLoc.y + templateImage.rows), Scalar::all(0), 2, 8, 0);
	rectangle(result, matchLoc, Point(matchLoc.x + templateImage.cols, matchLoc.y + templateImage.rows), Scalar::all(0), 2, 8, 0);

	/*showImage("Image", imageDisplay);
	showImage("Result", result);
	waitKey(0);*/

	//return result;
	return imageDisplay;
}

int digitRecognition(Mat image) {
	// TODO: recognise numbers from sign
	// Statistical Pattern Recognition
	// Scene Text Recognition - OCRTesseract
	// Template Matching
	// Chamfer Matching
	// Haar Classifiers

	return 0;
}<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <fstream>
#include <stack>
using namespace std;

/*
Strongly Connected Components of a Undirected Graph.
-v & w are SCC if there's a path from v to w and from w to v.

Kosaraju Algorithm (DOUBLE PASS DFS, linear time E+V):
inverse graph G -> R
dfs to obtain reversed post order of R
dfs G in the order given by reverse post order of R and mark in an array (array[nodeid]=SCC_id) the SCC id as we visit each node

*/

#define MAX 13

typedef vector<int> vi;
typedef vector<vi > vvi;

int visited[MAX]={0};
int visited2[MAX]={0};
int SCCids[MAX]={0};
stack<int> postOrder;

vvi graphG,graphR; //original and reversed graph

void dfs(int node){
	visited[node]=true;
	vi newVec = graphR[node];
	vi::iterator it;
	for(it=newVec.begin();it!=newVec.end();it++){
		int son=*it;
		if(visited[son]==false){
			dfs(son);
		}
	}
	postOrder.push(node);
}

void dfs_mark(int node, int SCCid){ //mark with SCC id
	visited2[node]=true;
	SCCids[node]=SCCid;
	vi newVec = graphG[node];
	vi::iterator it;
	for(it=newVec.begin();it!=newVec.end();it++){
		int son=*it;
		if(visited2[son]==false){
			dfs_mark(son,SCCid);
		}
	}
}

int main()
{
	ifstream fin ("graph1.txt");

	for(int i=0;i<MAX;i++){
		vi newVecG,newVecR;
		graphG.push_back(newVecG);
		graphR.push_back(newVecR);
	}

	int node1,node2;
	while(fin>>node1>>node2){
		//cout<<node1<<" "<<node2<<endl;
		graphG[node1].push_back(node2);
		graphR[node2].push_back(node1);
	}

	for(int i=0;i<MAX;i++){
		if(visited[i]==false){
			dfs(i);
		}
	}

	cout<<"Reversed PostOrder of R"<<endl;
	int SCCid=0;
	while(!postOrder.empty()){
		int node=postOrder.top();
		postOrder.pop();
		//cout<<node<<endl;
		if(visited2[node]==false){
			dfs_mark(node,SCCid);
			SCCid++;
		}
	}

	cout<<"Node\tSCCid"<<endl;
	for(int i=0;i<MAX;i++){
		cout<<i<<"\t"<<SCCids[i]<<endl;
	}

	return 0;
}

<commit_msg>TARJAN for SCC<commit_after>#include <iostream>
#include <vector>
#include <fstream>
#include <stack>
using namespace std;

/*
Strongly Connected Components of a Undirected Graph.
-v & w are SCC if there's a path from v to w and from w to v.

Kosaraju Algorithm (DOUBLE PASS DFS, linear time E+V):
inverse graph G -> R
dfs to obtain reversed post order of R
dfs G in the order given by reverse post order of R and mark in an array (array[nodeid]=SCC_id) the SCC id as we visit each node

*/

#define MAX 13

typedef vector<int> vi;
typedef vector<vi > vvi;

int visited[MAX]={0};
int visited2[MAX]={0};
int SCCids[MAX]={0};
stack<int> postOrder;

vvi graphG,graphR; //original and reversed graph

void dfs(int node){
	visited[node]=true;
	vi newVec = graphR[node];
	vi::iterator it;
	for(it=newVec.begin();it!=newVec.end();it++){
		int son=*it;
		if(visited[son]==false){
			dfs(son);
		}
	}
	postOrder.push(node);
}

void dfs_mark(int node, int SCCid){ //mark with SCC id
	visited2[node]=true;
	SCCids[node]=SCCid;
	vi newVec = graphG[node];
	vi::iterator it;
	for(it=newVec.begin();it!=newVec.end();it++){
		int son=*it;
		if(visited2[son]==false){
			dfs_mark(son,SCCid);
		}
	}
}

int main()
{
	ifstream fin ("graph2.txt"); //graph1.txt

	for(int i=0;i<MAX;i++){
		vi newVecG,newVecR;
		graphG.push_back(newVecG);
		graphR.push_back(newVecR);
	}

	int node1,node2;
	while(fin>>node1>>node2){
		//cout<<node1<<" "<<node2<<endl;
		graphG[node1].push_back(node2);
		graphR[node2].push_back(node1);
	}

	for(int i=0;i<MAX;i++){
		if(visited[i]==false){
			dfs(i);
		}
	}

	cout<<"Reversed PostOrder of R"<<endl;
	int SCCid=0;
	while(!postOrder.empty()){
		int node=postOrder.top();
		postOrder.pop();
		//cout<<node<<endl;
		if(visited2[node]==false){
			dfs_mark(node,SCCid);
			SCCid++;
		}
	}

	cout<<"Node\tSCCid"<<endl;
	for(int i=0;i<MAX;i++){
		cout<<i<<"\t"<<SCCids[i]<<endl;
	}

	return 0;
}

<|endoftext|>


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

  Program:   ParaView
  Module:    testRegistry.cxx

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "kwsysPrivate.h"

#include KWSYS_HEADER(Registry.hxx)
#include KWSYS_HEADER(ios/iostream)
#include <string.h>

// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
# include "Registry.hxx.in"
# include "kwsys_ios_iostream.h.in"
#endif

#define IFT(x,res) if ( !x )                    \
  {                                             \
  res = 1;                                      \
  kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl;           \
  }
#define IFNT(x,res) if ( x )                    \
  {                                             \
  res = 1;                                      \
  kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl;           \
  }

#define CHE(x,y,res) if ( x && y && strcmp(x,y) )                 \
  {                                                     \
  res = 1;                                              \
  kwsys_ios::cout << "Error, " << x << " != " << y << kwsys_ios::endl;        \
  }

int testRegistry(int, char*[])
{
  int res = 0;

  kwsys::Registry reg;
  reg.SetTopLevel("TestRegistry");

  IFT(reg.SetValue("TestSubkey",  "TestKey1", "Test Value 1"), res);
  IFT(reg.SetValue("TestSubkey1", "TestKey2", "Test Value 2"), res);
  IFT(reg.SetValue("TestSubkey",  "TestKey3", "Test Value 3"), res);
  IFT(reg.SetValue("TestSubkey2", "TestKey4", "Test Value 4"), res);

  const char *buffer;
  IFT(reg.ReadValue("TestSubkey",  "TestKey1", &buffer), res);
  CHE(buffer, "Test Value 1", res);
  IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res);
  CHE(buffer, "Test Value 2", res);
  IFT(reg.ReadValue("TestSubkey",  "TestKey3", &buffer), res);
  CHE(buffer, "Test Value 3", res);
  IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res);
  CHE(buffer, "Test Value 4", res);

  IFT(reg.SetValue("TestSubkey",  "TestKey1", "New Test Value 1"), res);
  IFT(reg.SetValue("TestSubkey1", "TestKey2", "New Test Value 2"), res);
  IFT(reg.SetValue("TestSubkey",  "TestKey3", "New Test Value 3"), res);
  IFT(reg.SetValue("TestSubkey2", "TestKey4", "New Test Value 4"), res);

  IFT(reg.ReadValue("TestSubkey",  "TestKey1", &buffer), res);
  CHE(buffer, "New Test Value 1", res);
  IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res);
  CHE(buffer, "New Test Value 2", res);
  IFT(reg.ReadValue("TestSubkey",  "TestKey3", &buffer), res);
  CHE(buffer, "New Test Value 3", res);
  IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res);
  CHE(buffer, "New Test Value 4", res);

  IFT( reg.DeleteValue("TestSubkey",  "TestKey1"), res);
  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey1", &buffer), res);
  IFT( reg.DeleteValue("TestSubkey1", "TestKey2"), res);
  IFNT(reg.ReadValue(  "TestSubkey1", "TestKey2", &buffer), res);
  IFT( reg.DeleteValue("TestSubkey",  "TestKey3"), res);
  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey3", &buffer), res);
  IFT( reg.DeleteValue("TestSubkey2", "TestKey4"), res);
  IFNT(reg.ReadValue(  "TestSubkey2", "TestKey5", &buffer), res);

  const char* longStringWithNewLines = "Value with embedded CR and LF characters CR='\015' LF='\012' CRLF='\015\012'";
  IFT(reg.SetValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName",  "TestKey1", longStringWithNewLines), res);
  IFT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res);
  CHE(buffer, longStringWithNewLines, res);
  IFT(reg.DeleteValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName",  "TestKey1"), res);
  IFNT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res);

  IFT(reg.SetValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", "Some value"), res);
  IFT(reg.ReadValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", &buffer), res);
  CHE(buffer, "Some value", res);
  IFT(reg.DeleteValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1"), res);
  IFNT(reg.ReadValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", &buffer), res);

  if ( res )
    {
    kwsys_ios::cout << "Test failed" << kwsys_ios::endl;
    }
  else
    {
    kwsys_ios::cout << "Test passed" << kwsys_ios::endl;
    }
  return res;
}
<commit_msg>COMP: remove warning on new HPUX compiler<commit_after>/*=========================================================================

  Program:   ParaView
  Module:    testRegistry.cxx

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "kwsysPrivate.h"

#include KWSYS_HEADER(Registry.hxx)
#include KWSYS_HEADER(ios/iostream)
#include <string.h>

// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
# include "Registry.hxx.in"
# include "kwsys_ios_iostream.h.in"
#endif

#define IFT(x,res) if ( !x )                    \
  {                                             \
  res = 1;                                      \
  kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl;           \
  }
#define IFNT(x,res) if ( x )                    \
  {                                             \
  res = 1;                                      \
  kwsys_ios::cout << "Error in: " << #x << kwsys_ios::endl;           \
  }

#define CHE(x,y,res) if ( x && strcmp(x,y) )                 \
  {                                                     \
  res = 1;                                              \
  kwsys_ios::cout << "Error, " << x << " != " << y << kwsys_ios::endl;        \
  }

int testRegistry(int, char*[])
{
  int res = 0;

  kwsys::Registry reg;
  reg.SetTopLevel("TestRegistry");

  IFT(reg.SetValue("TestSubkey",  "TestKey1", "Test Value 1"), res);
  IFT(reg.SetValue("TestSubkey1", "TestKey2", "Test Value 2"), res);
  IFT(reg.SetValue("TestSubkey",  "TestKey3", "Test Value 3"), res);
  IFT(reg.SetValue("TestSubkey2", "TestKey4", "Test Value 4"), res);

  const char *buffer;
  IFT(reg.ReadValue("TestSubkey",  "TestKey1", &buffer), res);
  CHE(buffer, "Test Value 1", res);
  IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res);
  CHE(buffer, "Test Value 2", res);
  IFT(reg.ReadValue("TestSubkey",  "TestKey3", &buffer), res);
  CHE(buffer, "Test Value 3", res);
  IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res);
  CHE(buffer, "Test Value 4", res);

  IFT(reg.SetValue("TestSubkey",  "TestKey1", "New Test Value 1"), res);
  IFT(reg.SetValue("TestSubkey1", "TestKey2", "New Test Value 2"), res);
  IFT(reg.SetValue("TestSubkey",  "TestKey3", "New Test Value 3"), res);
  IFT(reg.SetValue("TestSubkey2", "TestKey4", "New Test Value 4"), res);

  IFT(reg.ReadValue("TestSubkey",  "TestKey1", &buffer), res);
  CHE(buffer, "New Test Value 1", res);
  IFT(reg.ReadValue("TestSubkey1", "TestKey2", &buffer), res);
  CHE(buffer, "New Test Value 2", res);
  IFT(reg.ReadValue("TestSubkey",  "TestKey3", &buffer), res);
  CHE(buffer, "New Test Value 3", res);
  IFT(reg.ReadValue("TestSubkey2", "TestKey4", &buffer), res);
  CHE(buffer, "New Test Value 4", res);

  IFT( reg.DeleteValue("TestSubkey",  "TestKey1"), res);
  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey1", &buffer), res);
  IFT( reg.DeleteValue("TestSubkey1", "TestKey2"), res);
  IFNT(reg.ReadValue(  "TestSubkey1", "TestKey2", &buffer), res);
  IFT( reg.DeleteValue("TestSubkey",  "TestKey3"), res);
  IFNT(reg.ReadValue(  "TestSubkey",  "TestKey3", &buffer), res);
  IFT( reg.DeleteValue("TestSubkey2", "TestKey4"), res);
  IFNT(reg.ReadValue(  "TestSubkey2", "TestKey5", &buffer), res);

  const char* longStringWithNewLines = "Value with embedded CR and LF characters CR='\015' LF='\012' CRLF='\015\012'";
  IFT(reg.SetValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName",  "TestKey1", longStringWithNewLines), res);
  IFT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res);
  CHE(buffer, longStringWithNewLines, res);
  IFT(reg.DeleteValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName",  "TestKey1"), res);
  IFNT(reg.ReadValue("TestSubkeyWithVeryLongInFactSoLongItsHardToImagineAnybodyWouldReallyDoItLongName", "TestKey1", &buffer), res);

  IFT(reg.SetValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", "Some value"), res);
  IFT(reg.ReadValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", &buffer), res);
  CHE(buffer, "Some value", res);
  IFT(reg.DeleteValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1"), res);
  IFNT(reg.ReadValue("TestSubkeyWith = EqualSignChar",  "TestKey = 1", &buffer), res);

  if ( res )
    {
    kwsys_ios::cout << "Test failed" << kwsys_ios::endl;
    }
  else
    {
    kwsys_ios::cout << "Test passed" << kwsys_ios::endl;
    }
  return res;
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2010, The Cinder Project, All rights reserved.

 This code is intended for use with the Cinder C++ library: http://libcinder.org

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

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

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/Clipboard.h"
#include "cinder/Unicode.h"
#include "cinder/Log.h"
#if defined( CINDER_MAC )
	#include "cinder/cocoa/CinderCocoa.h"
	#import <Cocoa/Cocoa.h>
	#import <AppKit/NSPasteboard.h>
	#import <AppKit/NSImage.h>
#elif defined( CINDER_COCOA_TOUCH )
	#include "cinder/cocoa/CinderCocoa.h"
	#include "cinder/cocoa/CinderCocoaTouch.h"
	#import <UIKit/UIPasteboard.h>
#elif defined( CINDER_MSW )
	#include <windows.h>
	#define max(a, b) (((a) > (b)) ? (a) : (b))
	#define min(a, b) (((a) < (b)) ? (a) : (b))
	#include <gdiplus.h>
	#undef min
	#undef max
	#include "cinder/msw/CinderMsw.h"
	#include "cinder/msw/CinderMswGdiPlus.h"
	#include "cinder/Utilities.h"
	#include "cinder/ip/Fill.h"
	#include "cinder/ip/Blend.h"
	#include <set>
#endif

namespace cinder {

#if defined( CINDER_MSW )
bool clipboardContainsFormat( const std::set<UINT> &formats )
{
	bool result = false;
	if( ! ::OpenClipboard( NULL ) )
		return false;
	int numFormats = ::CountClipboardFormats();
	for( int f = 0; f < numFormats; ++f ) {
		if( formats.find( ::EnumClipboardFormats( f ) ) != formats.end() ) {
			result = true;
			break;
		}
	}
	::CloseClipboard();
	return result;
}

#endif

bool Clipboard::hasString()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
    NSDictionary *options = [NSDictionary dictionary];

	return [pasteboard canReadObjectForClasses:classArray options:options];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	return [pasteboard containsPasteboardTypes:UIPasteboardTypeListString];
#elif defined( CINDER_MSW )
	std::set<UINT> textFormats;
	textFormats.insert( CF_TEXT ); textFormats.insert( CF_UNICODETEXT ); textFormats.insert( CF_OEMTEXT );
	return clipboardContainsFormat( textFormats );
#endif
}

bool Clipboard::hasImage()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSArray *classArray = [NSArray arrayWithObject:[NSImage class]];
    NSDictionary *options = [NSDictionary dictionary];

	return [pasteboard canReadObjectForClasses:classArray options:options];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	return [pasteboard containsPasteboardTypes:UIPasteboardTypeListImage];
#elif defined( CINDER_MSW )
	std::set<UINT> imageFormats;
	imageFormats.insert( CF_BITMAP ); imageFormats.insert( CF_DIB ); imageFormats.insert( CF_DIBV5 );
	return clipboardContainsFormat( imageFormats);
#endif
}

std::string	Clipboard::getString()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
    NSDictionary *options = [NSDictionary dictionary];

	if( [pasteboard canReadObjectForClasses:classArray options:options] ) {
		NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
        NSString *text = [objectsToPaste firstObject];
		if( ! text )
			return std::string();
		else
			return cocoa::convertNsString( text );
	}
	else {
		return std::string();
	}
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	NSString *str = pasteboard.string;
	if( str )
		return cocoa::convertNsString( str );
	else
		return std::string();
#elif defined( CINDER_MSW )
	std::string result;
	if( ! ::OpenClipboard( NULL ) )
		return result;
	HANDLE dataH = ::GetClipboardData( CF_UNICODETEXT );
	if( dataH ) {
		wchar_t *pstr = reinterpret_cast<wchar_t*>( ::GlobalLock( dataH ) );
		if( pstr ) {
			std::wstring wstr( pstr );
			result = toUtf8( (char16_t*)wstr.c_str() );
			::GlobalUnlock( dataH );
		}
	}
	::CloseClipboard();
	return result;
#endif
}

ImageSourceRef Clipboard::getImage()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithPasteboard:pasteboard];
	if( rep )
		return cocoa::ImageSourceCgImage::createRef( [rep CGImage] );
	else
		return ImageSourceRef();
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	UIImage *image = pasteboard.image;
	if( image )
		return ImageSourceRef( *cocoa::convertUiImage( image ) );
	else
		return ImageSourceRef();
#elif defined( CINDER_MSW )
	ImageSourceRef result;
	if( ! ::OpenClipboard( NULL ) )
		return ImageSourceRef();
	HANDLE dataH = ::GetClipboardData( CF_DIBV5 );
	if( dataH ) {
		uint8_t *data = reinterpret_cast<uint8_t*>( ::GlobalLock( dataH ) );
		// CF_DIBV5 is composed of a BITMAPV5HEADER + bitmap data
		Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromBITMAPINFO( reinterpret_cast<BITMAPINFO*>( data ), data + sizeof(BITMAPV5HEADER) );
		if( bmp ) {
			result = ImageSourceRef( msw::convertGdiplusBitmap( *bmp ) );
			delete bmp;
		}
		::GlobalUnlock( dataH );
	}
	::CloseClipboard();
	return result;
#endif
}

void Clipboard::setString( const std::string &str )
{
#if defined( CINDER_MAC )
	[[NSPasteboard generalPasteboard] declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner:nil];
	[[NSPasteboard generalPasteboard] setString:[NSString stringWithUTF8String:str.c_str()] forType: NSStringPboardType];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	pasteboard.string = [NSString stringWithUTF8String:str.c_str()];
#elif defined( CINDER_MSW )
	if( ! ::OpenClipboard( NULL ) ) {
		CI_LOG_E( "Failed to open clipboard" );
		return;
	}
	::EmptyClipboard();
	std::u16string wstr = toUtf16( str );
	HANDLE hglbCopy = ::GlobalAlloc( GMEM_MOVEABLE, sizeof(uint16_t) * (wstr.length()+1) );
	// Lock the handle and copy the text to the buffer.
	void *lptstrCopy = ::GlobalLock( hglbCopy );
	memcpy( lptstrCopy, &wstr[0], sizeof(uint16_t) * (wstr.length()+1) );
	::GlobalUnlock( hglbCopy );
	::SetClipboardData( CF_UNICODETEXT, hglbCopy );
	::CloseClipboard();
#endif
}

void Clipboard::setImage( ImageSourceRef imageSource, ImageTarget::Options options )
{
#if defined( CINDER_MAC )
	cocoa::ImageTargetCgImageRef target = cocoa::ImageTargetCgImage::createRef( imageSource, options );
	imageSource->load( target );
	target->finalize();

	NSBitmapImageRep *imageRep = [[[NSBitmapImageRep alloc] initWithCGImage:target->getCgImage()] autorelease];
	NSImage *image = [[NSImage alloc] initWithSize:[imageRep size]];
	[image addRepresentation: imageRep];
	[[NSPasteboard generalPasteboard] declareTypes: [NSArray arrayWithObject: NSTIFFPboardType] owner:nil];
	[[NSPasteboard generalPasteboard] setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
	[image release];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	cocoa::SafeUiImage uiImage = cocoa::createUiImage( imageSource );
	pasteboard.image = (UIImage*)uiImage;
#elif defined( CINDER_MSW )
	if( ! ::OpenClipboard( NULL ) ) {
		CI_LOG_E( "Failed to open clipboard" );
		return;
	}
	::EmptyClipboard();
	int32_t rowBytes = (( imageSource->getWidth() * 32 + 31 ) / 32 ) * 4;
	size_t dataSize = sizeof(BITMAPV5HEADER) + imageSource->getHeight() * rowBytes;
	HANDLE hglbCopy = ::GlobalAlloc( GMEM_MOVEABLE, dataSize );
	uint8_t *destData = reinterpret_cast<uint8_t*>( ::GlobalLock( hglbCopy ) );

	// we create 'tempSurface' convert 'imageSource' into a Surface8u
	// then alpha blend 'tempSurface' into 'destSurface'.
	// Unfortunately alpha on Win32 Clipboard just seems to be a total mess, so we're punting and forcing it to be opaque on black.
	SurfaceChannelOrder sco = SurfaceChannelOrder::BGRA;
	const Surface8u tempSurface( imageSource );
	Surface8u destSurface( destData + sizeof(BITMAPV5HEADER), imageSource->getWidth(), imageSource->getHeight(), rowBytes, sco );
	ip::fill( &destSurface, ColorA8u( 0, 0, 0, 255 ) );
	ip::blend( &destSurface, tempSurface );

	// set the BITMAPV5HEADER based on 'destSurface'
	BITMAPV5HEADER bi = {0};
	bi.bV5Size          = sizeof(BITMAPV5HEADER);
	bi.bV5Width         = destSurface.getWidth();
	bi.bV5Height        = -destSurface.getHeight();
	bi.bV5Planes        = 1;
	bi.bV5BitCount      = 32;
	bi.bV5Compression   = BI_RGB;
	bi.bV5SizeImage     = destSurface.getHeight() * rowBytes;
	bi.bV5XPelsPerMeter = 0;
	bi.bV5YPelsPerMeter = 0;
	bi.bV5ClrUsed       = 0;
	bi.bV5ClrImportant  = 0;
	bi.bV5BlueMask      = 0x000000ff;
	bi.bV5GreenMask     = 0x0000ff00;
	bi.bV5RedMask       = 0x00ff0000;
	bi.bV5AlphaMask     = 0xff000000;
	bi.bV5CSType        = LCS_sRGB;
	bi.bV5Intent        = LCS_GM_IMAGES;
	*(reinterpret_cast<BITMAPV5HEADER*>(destData)) = bi;

	::GlobalUnlock( hglbCopy );
	::SetClipboardData( CF_DIBV5, hglbCopy );
	::CloseClipboard();
#endif
}

} // namespace cinder<commit_msg>add a cast to avoid a warning<commit_after>/*
 Copyright (c) 2010, The Cinder Project, All rights reserved.

 This code is intended for use with the Cinder C++ library: http://libcinder.org

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

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

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/Clipboard.h"
#include "cinder/Unicode.h"
#include "cinder/Log.h"
#if defined( CINDER_MAC )
	#include "cinder/cocoa/CinderCocoa.h"
	#import <Cocoa/Cocoa.h>
	#import <AppKit/NSPasteboard.h>
	#import <AppKit/NSImage.h>
#elif defined( CINDER_COCOA_TOUCH )
	#include "cinder/cocoa/CinderCocoa.h"
	#include "cinder/cocoa/CinderCocoaTouch.h"
	#import <UIKit/UIPasteboard.h>
#elif defined( CINDER_MSW )
	#include <windows.h>
	#define max(a, b) (((a) > (b)) ? (a) : (b))
	#define min(a, b) (((a) < (b)) ? (a) : (b))
	#include <gdiplus.h>
	#undef min
	#undef max
	#include "cinder/msw/CinderMsw.h"
	#include "cinder/msw/CinderMswGdiPlus.h"
	#include "cinder/Utilities.h"
	#include "cinder/ip/Fill.h"
	#include "cinder/ip/Blend.h"
	#include <set>
#endif

namespace cinder {

#if defined( CINDER_MSW )
bool clipboardContainsFormat( const std::set<UINT> &formats )
{
	bool result = false;
	if( ! ::OpenClipboard( NULL ) )
		return false;
	int numFormats = ::CountClipboardFormats();
	for( int f = 0; f < numFormats; ++f ) {
		if( formats.find( ::EnumClipboardFormats( f ) ) != formats.end() ) {
			result = true;
			break;
		}
	}
	::CloseClipboard();
	return result;
}

#endif

bool Clipboard::hasString()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
    NSDictionary *options = [NSDictionary dictionary];

	return [pasteboard canReadObjectForClasses:classArray options:options];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	return [pasteboard containsPasteboardTypes:UIPasteboardTypeListString];
#elif defined( CINDER_MSW )
	std::set<UINT> textFormats;
	textFormats.insert( CF_TEXT ); textFormats.insert( CF_UNICODETEXT ); textFormats.insert( CF_OEMTEXT );
	return clipboardContainsFormat( textFormats );
#endif
}

bool Clipboard::hasImage()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSArray *classArray = [NSArray arrayWithObject:[NSImage class]];
    NSDictionary *options = [NSDictionary dictionary];

	return [pasteboard canReadObjectForClasses:classArray options:options];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	return [pasteboard containsPasteboardTypes:UIPasteboardTypeListImage];
#elif defined( CINDER_MSW )
	std::set<UINT> imageFormats;
	imageFormats.insert( CF_BITMAP ); imageFormats.insert( CF_DIB ); imageFormats.insert( CF_DIBV5 );
	return clipboardContainsFormat( imageFormats);
#endif
}

std::string	Clipboard::getString()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
    NSDictionary *options = [NSDictionary dictionary];

	if( [pasteboard canReadObjectForClasses:classArray options:options] ) {
		NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
        NSString *text = [objectsToPaste firstObject];
		if( ! text )
			return std::string();
		else
			return cocoa::convertNsString( text );
	}
	else {
		return std::string();
	}
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	NSString *str = pasteboard.string;
	if( str )
		return cocoa::convertNsString( str );
	else
		return std::string();
#elif defined( CINDER_MSW )
	std::string result;
	if( ! ::OpenClipboard( NULL ) )
		return result;
	HANDLE dataH = ::GetClipboardData( CF_UNICODETEXT );
	if( dataH ) {
		wchar_t *pstr = reinterpret_cast<wchar_t*>( ::GlobalLock( dataH ) );
		if( pstr ) {
			std::wstring wstr( pstr );
			result = toUtf8( (char16_t*)wstr.c_str() );
			::GlobalUnlock( dataH );
		}
	}
	::CloseClipboard();
	return result;
#endif
}

ImageSourceRef Clipboard::getImage()
{
#if defined( CINDER_MAC )
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSBitmapImageRep *rep = (NSBitmapImageRep*)[NSBitmapImageRep imageRepWithPasteboard:pasteboard];
	if( rep )
		return cocoa::ImageSourceCgImage::createRef( [rep CGImage] );
	else
		return ImageSourceRef();
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	UIImage *image = pasteboard.image;
	if( image )
		return ImageSourceRef( *cocoa::convertUiImage( image ) );
	else
		return ImageSourceRef();
#elif defined( CINDER_MSW )
	ImageSourceRef result;
	if( ! ::OpenClipboard( NULL ) )
		return ImageSourceRef();
	HANDLE dataH = ::GetClipboardData( CF_DIBV5 );
	if( dataH ) {
		uint8_t *data = reinterpret_cast<uint8_t*>( ::GlobalLock( dataH ) );
		// CF_DIBV5 is composed of a BITMAPV5HEADER + bitmap data
		Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromBITMAPINFO( reinterpret_cast<BITMAPINFO*>( data ), data + sizeof(BITMAPV5HEADER) );
		if( bmp ) {
			result = ImageSourceRef( msw::convertGdiplusBitmap( *bmp ) );
			delete bmp;
		}
		::GlobalUnlock( dataH );
	}
	::CloseClipboard();
	return result;
#endif
}

void Clipboard::setString( const std::string &str )
{
#if defined( CINDER_MAC )
	[[NSPasteboard generalPasteboard] declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner:nil];
	[[NSPasteboard generalPasteboard] setString:[NSString stringWithUTF8String:str.c_str()] forType: NSStringPboardType];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	pasteboard.string = [NSString stringWithUTF8String:str.c_str()];
#elif defined( CINDER_MSW )
	if( ! ::OpenClipboard( NULL ) ) {
		CI_LOG_E( "Failed to open clipboard" );
		return;
	}
	::EmptyClipboard();
	std::u16string wstr = toUtf16( str );
	HANDLE hglbCopy = ::GlobalAlloc( GMEM_MOVEABLE, sizeof(uint16_t) * (wstr.length()+1) );
	// Lock the handle and copy the text to the buffer.
	void *lptstrCopy = ::GlobalLock( hglbCopy );
	memcpy( lptstrCopy, &wstr[0], sizeof(uint16_t) * (wstr.length()+1) );
	::GlobalUnlock( hglbCopy );
	::SetClipboardData( CF_UNICODETEXT, hglbCopy );
	::CloseClipboard();
#endif
}

void Clipboard::setImage( ImageSourceRef imageSource, ImageTarget::Options options )
{
#if defined( CINDER_MAC )
	cocoa::ImageTargetCgImageRef target = cocoa::ImageTargetCgImage::createRef( imageSource, options );
	imageSource->load( target );
	target->finalize();

	NSBitmapImageRep *imageRep = [[[NSBitmapImageRep alloc] initWithCGImage:target->getCgImage()] autorelease];
	NSImage *image = [[NSImage alloc] initWithSize:[imageRep size]];
	[image addRepresentation: imageRep];
	[[NSPasteboard generalPasteboard] declareTypes: [NSArray arrayWithObject: NSTIFFPboardType] owner:nil];
	[[NSPasteboard generalPasteboard] setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
	[image release];
#elif defined( CINDER_COCOA_TOUCH )
	UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
	cocoa::SafeUiImage uiImage = cocoa::createUiImage( imageSource );
	pasteboard.image = (UIImage*)uiImage;
#elif defined( CINDER_MSW )
	if( ! ::OpenClipboard( NULL ) ) {
		CI_LOG_E( "Failed to open clipboard" );
		return;
	}
	::EmptyClipboard();
	int32_t rowBytes = (( imageSource->getWidth() * 32 + 31 ) / 32 ) * 4;
	size_t dataSize = sizeof(BITMAPV5HEADER) + imageSource->getHeight() * rowBytes;
	HANDLE hglbCopy = ::GlobalAlloc( GMEM_MOVEABLE, dataSize );
	uint8_t *destData = reinterpret_cast<uint8_t*>( ::GlobalLock( hglbCopy ) );

	// we create 'tempSurface' convert 'imageSource' into a Surface8u
	// then alpha blend 'tempSurface' into 'destSurface'.
	// Unfortunately alpha on Win32 Clipboard just seems to be a total mess, so we're punting and forcing it to be opaque on black.
	SurfaceChannelOrder sco = SurfaceChannelOrder::BGRA;
	const Surface8u tempSurface( imageSource );
	Surface8u destSurface( destData + sizeof(BITMAPV5HEADER), imageSource->getWidth(), imageSource->getHeight(), rowBytes, sco );
	ip::fill( &destSurface, ColorA8u( 0, 0, 0, 255 ) );
	ip::blend( &destSurface, tempSurface );

	// set the BITMAPV5HEADER based on 'destSurface'
	BITMAPV5HEADER bi = {0};
	bi.bV5Size          = sizeof(BITMAPV5HEADER);
	bi.bV5Width         = destSurface.getWidth();
	bi.bV5Height        = -destSurface.getHeight();
	bi.bV5Planes        = 1;
	bi.bV5BitCount      = 32;
	bi.bV5Compression   = BI_RGB;
	bi.bV5SizeImage     = destSurface.getHeight() * rowBytes;
	bi.bV5XPelsPerMeter = 0;
	bi.bV5YPelsPerMeter = 0;
	bi.bV5ClrUsed       = 0;
	bi.bV5ClrImportant  = 0;
	bi.bV5BlueMask      = 0x000000ff;
	bi.bV5GreenMask     = 0x0000ff00;
	bi.bV5RedMask       = 0x00ff0000;
	bi.bV5AlphaMask     = 0xff000000;
	bi.bV5CSType        = LCS_sRGB;
	bi.bV5Intent        = LCS_GM_IMAGES;
	*(reinterpret_cast<BITMAPV5HEADER*>(destData)) = bi;

	::GlobalUnlock( hglbCopy );
	::SetClipboardData( CF_DIBV5, hglbCopy );
	::CloseClipboard();
#endif
}

} // namespace cinder<|endoftext|>


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

#include "elements/logic/pid.h"

namespace spaghetti::elements::logic {

PID::PID()
  : Element{}
{
  setMinInputs(7);
  setMaxInputs(7);
  setMinOutputs(1);
  setMaxOutputs(1);

  addInput(ValueType::eFloat, "PV", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "SP", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "KP", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "KI", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "KD", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "CV High", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "CV Low", IOSocket::eCanHoldFloat);

  addOutput(ValueType::eFloat, "CV", IOSocket::eCanHoldFloat);
}

void PID::update(duration_t const &a_delta)
{
  m_delta = static_cast<float>(a_delta.count()) / 1000.f;
}

void PID::calculate()
{
  float const PV{ std::get<float>(m_inputs[0].value) };
  float const SP{ std::get<float>(m_inputs[1].value) };
  float const KP{ std::get<float>(m_inputs[2].value) };
  float const KI{ std::get<float>(m_inputs[3].value) };
  float const KD{ std::get<float>(m_inputs[4].value) };
  float const CV_HIGH{ std::get<float>(m_inputs[5].value) };
  float const CV_LOW{ std::get<float>(m_inputs[6].value) };

  float const ERROR{ SP - PV };

  m_integral += ERROR * m_delta;

  float const P{ KP * ERROR };
  float const I{ KI * m_integral };
  float const D{ KD * ((ERROR - m_lastError) / m_delta) };

  float const CV{ std::clamp(P + I + D, CV_LOW, CV_HIGH) };

  m_lastError = ERROR;

  m_outputs[0].value = CV;
}

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

#include "elements/logic/pid.h"

namespace spaghetti::elements::logic {

PID::PID()
  : Element{}
{
  setMinInputs(7);
  setMaxInputs(7);
  setMinOutputs(1);
  setMaxOutputs(1);

  addInput(ValueType::eFloat, "PV", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "SP", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "KP", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "KI", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "KD", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "CV High", IOSocket::eCanHoldFloat);
  addInput(ValueType::eFloat, "CV Low", IOSocket::eCanHoldFloat);

  addOutput(ValueType::eFloat, "CV", IOSocket::eCanHoldFloat);
}

void PID::update(duration_t const &a_delta)
{
  m_delta = static_cast<float>(a_delta.count()) / 1000.f;
}

void PID::calculate()
{
  float const PV{ std::get<float>(m_inputs[0].value) };
  float const SP{ std::get<float>(m_inputs[1].value) };
  float const KP{ std::get<float>(m_inputs[2].value) };
  float const KI{ std::get<float>(m_inputs[3].value) };
  float const KD{ std::get<float>(m_inputs[4].value) };
  float const CV_HIGH{ std::get<float>(m_inputs[5].value) };
  float const CV_LOW{ std::get<float>(m_inputs[6].value) };

  float const ERROR{ SP - PV };

  m_integral += (ERROR * m_delta) / KI;
  m_integral = std::clamp(m_integral, CV_LOW, CV_HIGH);

  float const P{ KP * ERROR };
  float const I{ m_integral };
  float const D{ KD * ((ERROR - m_lastError) / m_delta) };

  float const CV{ std::clamp(P + I + D, CV_LOW, CV_HIGH) };

  m_lastError = ERROR;

  m_outputs[0].value = CV;
}

} // namespace spaghetti::elements::logic
<|endoftext|>