<commit_before>/*
 * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"
#include "debug_line.h"
#include "device.h"
#include "log.h"
#include "lua_environment.h"
#include "material_manager.h"
#include "resource_manager.h"
#include "resource_package.h"
#include "types.h"
#include "world.h"
#include "memory.h"
#include "os.h"

#define MAX_SUBSYSTEMS_HEAP 8 * 1024 * 1024

namespace crown
{
Device::Device(const ConfigSettings& cs, Filesystem& fs)
	: _allocator(default_allocator(), MAX_SUBSYSTEMS_HEAP)
	, _width(0)
	, _height(0)
	, _is_init(false)
	, _is_running(false)
	, _is_paused(false)
	, _frame_count(0)
	, _last_time(0)
	, _current_time(0)
	, _last_delta_time(0.0f)
	, _time_since_start(0.0)
	, _cs(cs)
	, _fs(fs)
	, _boot_package_id(cs.boot_package)
	, _boot_script_id(cs.boot_script)
	, _boot_package(NULL)
	, _lua_environment(NULL)
	, _resource_manager(NULL)
	, _worlds(default_allocator())
{
}

void Device::init()
{
	// Initialize
	CE_LOGI("Initializing Crown Engine %s...", version());

	// Create resource manager
	CE_LOGD("Creating resource manager...");
	_resource_manager = CE_NEW(_allocator, ResourceManager)(_fs);

	CE_LOGD("Creating material manager...");
	material_manager::init();
	debug_line::init();

	_lua_environment = CE_NEW(_allocator, LuaEnvironment)();
	_lua_environment->load_libs();

	CE_LOGD("Crown Engine initialized.");
	CE_LOGD("Initializing Game...");

	_is_init = true;
	_is_running = true;
	_last_time = os::clocktime();

	_boot_package = create_resource_package(_boot_package_id);
	_boot_package->load();
	_boot_package->flush();

	_lua_environment->execute((LuaResource*)_resource_manager->get(SCRIPT_TYPE, _boot_script_id));
	_lua_environment->call_global("init", 0);
}

void Device::shutdown()
{
	CE_ASSERT(_is_init, "Engine is not initialized");

	// Shutdowns the game
	_lua_environment->call_global("shutdown", 0);

	_boot_package->unload();
	destroy_resource_package(*_boot_package);

	CE_DELETE(_allocator, _lua_environment);

	CE_LOGD("Releasing material manager...");
	debug_line::shutdown();
	material_manager::shutdown();

	CE_LOGD("Releasing resource manager...");
	CE_DELETE(_allocator, _resource_manager);

	_allocator.clear();
	_is_init = false;
}

ResourceManager* Device::resource_manager()
{
	return _resource_manager;
}

LuaEnvironment* Device::lua_environment()
{
	return _lua_environment;
}

void Device::quit()
{
	_is_running = false;
}

void Device::pause()
{
	_is_paused = true;
	CE_LOGI("Engine paused.");
}

void Device::unpause()
{
	_is_paused = false;
	CE_LOGI("Engine unpaused.");
}

bool Device::is_running() const
{
	return _is_running;
}

uint64_t Device::frame_count() const
{
	return _frame_count;
}

float Device::last_delta_time() const
{
	return _last_delta_time;
}

double Device::time_since_start() const
{
	return _time_since_start;
}

void Device::update()
{
	_current_time = os::clocktime();
	const int64_t time = _current_time - _last_time;
	_last_time = _current_time;
	const double freq = (double) os::clockfrequency();
	_last_delta_time = time * (1.0 / freq);
	_time_since_start += _last_delta_time;

	if (!_is_paused)
	{
		_resource_manager->complete_requests();
		_lua_environment->call_global("update", 1, ARGUMENT_FLOAT, last_delta_time());
		_lua_environment->call_global("render", 1, ARGUMENT_FLOAT, last_delta_time());
	}

	_frame_count++;

	_lua_environment->clear_temporaries();
}

void Device::render_world(World& world, Camera* camera)
{
	world.render(camera);
}

World* Device::create_world()
{
	World* w = CE_NEW(default_allocator(), World)(*_resource_manager, *_lua_environment);
	array::push_back(_worlds, w);
	return w;
}

void Device::destroy_world(World& w)
{
	for (uint32_t i = 0, n = array::size(_worlds); i < n; ++i)
	{
		if (&w == _worlds[i])
		{
			CE_DELETE(default_allocator(), &w);
			_worlds[i] = _worlds[n - 1];
			array::pop_back(_worlds);
			return;
		}
	}

	CE_ASSERT(false, "Bad world");
}

ResourcePackage* Device::create_resource_package(StringId64 id)
{
	return CE_NEW(default_allocator(), ResourcePackage)(id, *_resource_manager);
}

void Device::destroy_resource_package(ResourcePackage& package)
{
	CE_DELETE(default_allocator(), &package);
}

void Device::reload(StringId64 type, StringId64 name)
{
}

namespace device_globals
{
	char _buffer[sizeof(Device)];
	Device* _device = NULL;

	void init(const ConfigSettings& cs, Filesystem& fs)
	{
		CE_ASSERT(_device == NULL, "Crown already initialized");
		_device = new (_buffer) Device(cs, fs);
	}

	void shutdown()
	{
		_device->~Device();
		_device = NULL;
	}
} // namespace device_globals

Device* device()
{
	return device_globals::_device;
}

} // namespace crown
<commit_msg>Add SCRIPT_TYPE reload<commit_after>/*
 * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "config.h"
#include "debug_line.h"
#include "device.h"
#include "log.h"
#include "lua_environment.h"
#include "material_manager.h"
#include "resource_manager.h"
#include "resource_package.h"
#include "types.h"
#include "world.h"
#include "memory.h"
#include "os.h"

#define MAX_SUBSYSTEMS_HEAP 8 * 1024 * 1024

namespace crown
{
Device::Device(const ConfigSettings& cs, Filesystem& fs)
	: _allocator(default_allocator(), MAX_SUBSYSTEMS_HEAP)
	, _width(0)
	, _height(0)
	, _is_init(false)
	, _is_running(false)
	, _is_paused(false)
	, _frame_count(0)
	, _last_time(0)
	, _current_time(0)
	, _last_delta_time(0.0f)
	, _time_since_start(0.0)
	, _cs(cs)
	, _fs(fs)
	, _boot_package_id(cs.boot_package)
	, _boot_script_id(cs.boot_script)
	, _boot_package(NULL)
	, _lua_environment(NULL)
	, _resource_manager(NULL)
	, _worlds(default_allocator())
{
}

void Device::init()
{
	// Initialize
	CE_LOGI("Initializing Crown Engine %s...", version());

	// Create resource manager
	CE_LOGD("Creating resource manager...");
	_resource_manager = CE_NEW(_allocator, ResourceManager)(_fs);

	CE_LOGD("Creating material manager...");
	material_manager::init();
	debug_line::init();

	_lua_environment = CE_NEW(_allocator, LuaEnvironment)();
	_lua_environment->load_libs();

	CE_LOGD("Crown Engine initialized.");
	CE_LOGD("Initializing Game...");

	_is_init = true;
	_is_running = true;
	_last_time = os::clocktime();

	_boot_package = create_resource_package(_boot_package_id);
	_boot_package->load();
	_boot_package->flush();

	_lua_environment->execute((LuaResource*)_resource_manager->get(SCRIPT_TYPE, _boot_script_id));
	_lua_environment->call_global("init", 0);
}

void Device::shutdown()
{
	CE_ASSERT(_is_init, "Engine is not initialized");

	// Shutdowns the game
	_lua_environment->call_global("shutdown", 0);

	_boot_package->unload();
	destroy_resource_package(*_boot_package);

	CE_DELETE(_allocator, _lua_environment);

	CE_LOGD("Releasing material manager...");
	debug_line::shutdown();
	material_manager::shutdown();

	CE_LOGD("Releasing resource manager...");
	CE_DELETE(_allocator, _resource_manager);

	_allocator.clear();
	_is_init = false;
}

ResourceManager* Device::resource_manager()
{
	return _resource_manager;
}

LuaEnvironment* Device::lua_environment()
{
	return _lua_environment;
}

void Device::quit()
{
	_is_running = false;
}

void Device::pause()
{
	_is_paused = true;
	CE_LOGI("Engine paused.");
}

void Device::unpause()
{
	_is_paused = false;
	CE_LOGI("Engine unpaused.");
}

bool Device::is_running() const
{
	return _is_running;
}

uint64_t Device::frame_count() const
{
	return _frame_count;
}

float Device::last_delta_time() const
{
	return _last_delta_time;
}

double Device::time_since_start() const
{
	return _time_since_start;
}

void Device::update()
{
	_current_time = os::clocktime();
	const int64_t time = _current_time - _last_time;
	_last_time = _current_time;
	const double freq = (double) os::clockfrequency();
	_last_delta_time = time * (1.0 / freq);
	_time_since_start += _last_delta_time;

	if (!_is_paused)
	{
		_resource_manager->complete_requests();
		_lua_environment->call_global("update", 1, ARGUMENT_FLOAT, last_delta_time());
		_lua_environment->call_global("render", 1, ARGUMENT_FLOAT, last_delta_time());
	}

	_frame_count++;

	_lua_environment->clear_temporaries();
}

void Device::render_world(World& world, Camera* camera)
{
	world.render(camera);
}

World* Device::create_world()
{
	World* w = CE_NEW(default_allocator(), World)(*_resource_manager, *_lua_environment);
	array::push_back(_worlds, w);
	return w;
}

void Device::destroy_world(World& w)
{
	for (uint32_t i = 0, n = array::size(_worlds); i < n; ++i)
	{
		if (&w == _worlds[i])
		{
			CE_DELETE(default_allocator(), &w);
			_worlds[i] = _worlds[n - 1];
			array::pop_back(_worlds);
			return;
		}
	}

	CE_ASSERT(false, "Bad world");
}

ResourcePackage* Device::create_resource_package(StringId64 id)
{
	return CE_NEW(default_allocator(), ResourcePackage)(id, *_resource_manager);
}

void Device::destroy_resource_package(ResourcePackage& package)
{
	CE_DELETE(default_allocator(), &package);
}

void Device::reload(StringId64 type, StringId64 name)
{
	const void* old_resource = _resource_manager->get(type, name);
	_resource_manager->reload(type, name);
	const void* new_resource = _resource_manager->get(type, name);

	if (type == SCRIPT_TYPE)
	{
		_lua_environment->execute((const LuaResource*)new_resource);
	}
}

namespace device_globals
{
	char _buffer[sizeof(Device)];
	Device* _device = NULL;

	void init(const ConfigSettings& cs, Filesystem& fs)
	{
		CE_ASSERT(_device == NULL, "Crown already initialized");
		_device = new (_buffer) Device(cs, fs);
	}

	void shutdown()
	{
		_device->~Device();
		_device = NULL;
	}
} // namespace device_globals

Device* device()
{
	return device_globals::_device;
}

} // namespace crown
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/chromedriver/chrome/devtools_http_client.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/json/json_reader.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
#include "chrome/test/chromedriver/chrome/log.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/version.h"
#include "chrome/test/chromedriver/chrome/web_view_impl.h"
#include "chrome/test/chromedriver/net/net_util.h"
#include "chrome/test/chromedriver/net/url_request_context_getter.h"

namespace {

Status FakeCloseFrontends() {
  return Status(kOk);
}

}  // namespace

WebViewInfo::WebViewInfo(const std::string& id,
                         const std::string& debugger_url,
                         const std::string& url,
                         Type type)
    : id(id), debugger_url(debugger_url), url(url), type(type) {}

WebViewInfo::~WebViewInfo() {}

bool WebViewInfo::IsFrontend() const {
  return url.find("chrome-devtools://") == 0u;
}

WebViewsInfo::WebViewsInfo() {}

WebViewsInfo::WebViewsInfo(const std::vector<WebViewInfo>& info)
    : views_info(info) {}

WebViewsInfo::~WebViewsInfo() {}

const WebViewInfo& WebViewsInfo::Get(int index) const {
  return views_info[index];
}

size_t WebViewsInfo::GetSize() const {
  return views_info.size();
}

const WebViewInfo* WebViewsInfo::GetForId(const std::string& id) const {
  for (size_t i = 0; i < views_info.size(); ++i) {
    if (views_info[i].id == id)
      return &views_info[i];
  }
  return NULL;
}

DevToolsHttpClient::DevToolsHttpClient(
    const NetAddress& address,
    scoped_refptr<URLRequestContextGetter> context_getter,
    const SyncWebSocketFactory& socket_factory)
    : context_getter_(context_getter),
      socket_factory_(socket_factory),
      server_url_("http://" + address.ToString()),
      web_socket_url_prefix_(base::StringPrintf(
          "ws://%s/devtools/page/", address.ToString().c_str())) {}

DevToolsHttpClient::~DevToolsHttpClient() {}

Status DevToolsHttpClient::Init(const base::TimeDelta& timeout) {
  base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
  std::string devtools_version;
  while (true) {
    Status status = GetVersion(&devtools_version);
    if (status.IsOk())
      break;
    if (status.code() != kChromeNotReachable ||
        base::TimeTicks::Now() > deadline) {
      return status;
    }
    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
  }

  int kToTBuildNo = 9999;
  if (devtools_version.empty()) {
    // Content Shell has an empty product version and a fake user agent.
    // There's no way to detect the actual version, so assume it is tip of tree.
    version_ = "content shell";
    build_no_ = kToTBuildNo;
    return Status(kOk);
  }
  if (devtools_version.find("Version/") == 0u) {
    version_ = "webview";
    build_no_ = kToTBuildNo;
    return Status(kOk);
  }
  std::string prefix = "Chrome/";
  if (devtools_version.find(prefix) != 0u) {
    return Status(kUnknownError,
                  "unrecognized Chrome version: " + devtools_version);
  }

  std::string stripped_version = devtools_version.substr(prefix.length());
  int temp_build_no;
  std::vector<std::string> version_parts;
  base::SplitString(stripped_version, '.', &version_parts);
  if (version_parts.size() != 4 ||
      !base::StringToInt(version_parts[2], &temp_build_no)) {
    return Status(kUnknownError,
                  "unrecognized Chrome version: " + devtools_version);
  }

  version_ = stripped_version;
  build_no_ = temp_build_no;
  return Status(kOk);
}

Status DevToolsHttpClient::GetWebViewsInfo(WebViewsInfo* views_info) {
  std::string data;
  if (!FetchUrlAndLog(server_url_ + "/json", context_getter_.get(), &data))
    return Status(kChromeNotReachable);

  return internal::ParseWebViewsInfo(data, views_info);
}

scoped_ptr<DevToolsClient> DevToolsHttpClient::CreateClient(
    const std::string& id) {
  return scoped_ptr<DevToolsClient>(new DevToolsClientImpl(
      socket_factory_,
      web_socket_url_prefix_ + id,
      id,
      base::Bind(
          &DevToolsHttpClient::CloseFrontends, base::Unretained(this), id)));
}

Status DevToolsHttpClient::CloseWebView(const std::string& id) {
  std::string data;
  if (!FetchUrlAndLog(
          server_url_ + "/json/close/" + id, context_getter_.get(), &data)) {
    return Status(kOk);  // Closing the last web view leads chrome to quit.
  }

  // Wait for the target window to be completely closed.
  base::TimeTicks deadline =
      base::TimeTicks::Now() + base::TimeDelta::FromSeconds(20);
  while (base::TimeTicks::Now() < deadline) {
    WebViewsInfo views_info;
    Status status = GetWebViewsInfo(&views_info);
    if (status.code() == kChromeNotReachable)
      return Status(kOk);
    if (status.IsError())
      return status;
    if (!views_info.GetForId(id))
      return Status(kOk);
    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
  }
  return Status(kUnknownError, "failed to close window in 20 seconds");
}

Status DevToolsHttpClient::ActivateWebView(const std::string& id) {
  std::string data;
  if (!FetchUrlAndLog(
          server_url_ + "/json/activate/" + id, context_getter_.get(), &data))
    return Status(kUnknownError, "cannot activate web view");
  return Status(kOk);
}

const std::string& DevToolsHttpClient::version() const {
  return version_;
}

int DevToolsHttpClient::build_no() const {
  return build_no_;
}

Status DevToolsHttpClient::GetVersion(std::string* version) {
  std::string data;
  if (!FetchUrlAndLog(
          server_url_ + "/json/version", context_getter_.get(), &data))
    return Status(kChromeNotReachable);

  return internal::ParseVersionInfo(data, version);
}

Status DevToolsHttpClient::CloseFrontends(const std::string& for_client_id) {
  WebViewsInfo views_info;
  Status status = GetWebViewsInfo(&views_info);
  if (status.IsError())
    return status;

  // Close frontends. Usually frontends are docked in the same page, although
  // some may be in tabs (undocked, chrome://inspect, the DevTools
  // discovery page, etc.). Tabs can be closed via the DevTools HTTP close
  // URL, but docked frontends can only be closed, by design, by connecting
  // to them and clicking the close button. Close the tab frontends first
  // in case one of them is debugging a docked frontend, which would prevent
  // the code from being able to connect to the docked one.
  std::list<std::string> tab_frontend_ids;
  std::list<std::string> docked_frontend_ids;
  for (size_t i = 0; i < views_info.GetSize(); ++i) {
    const WebViewInfo& view_info = views_info.Get(i);
    if (view_info.IsFrontend()) {
      if (view_info.type == WebViewInfo::kPage)
        tab_frontend_ids.push_back(view_info.id);
      else if (view_info.type == WebViewInfo::kOther)
        docked_frontend_ids.push_back(view_info.id);
      else
        return Status(kUnknownError, "unknown type of DevTools frontend");
    }
  }

  for (std::list<std::string>::const_iterator it = tab_frontend_ids.begin();
       it != tab_frontend_ids.end(); ++it) {
    status = CloseWebView(*it);
    if (status.IsError())
      return status;
  }

  for (std::list<std::string>::const_iterator it = docked_frontend_ids.begin();
       it != docked_frontend_ids.end(); ++it) {
    scoped_ptr<DevToolsClient> client(new DevToolsClientImpl(
        socket_factory_,
        web_socket_url_prefix_ + *it,
        *it,
        base::Bind(&FakeCloseFrontends)));
    scoped_ptr<WebViewImpl> web_view(
        new WebViewImpl(*it, build_no_, client.Pass()));

    status = web_view->ConnectIfNecessary();
    // Ignore disconnected error, because the debugger might have closed when
    // its container page was closed above.
    if (status.IsError() && status.code() != kDisconnected)
      return status;

    scoped_ptr<base::Value> result;
    status = web_view->EvaluateScript(
        std::string(),
        "document.querySelector('*[id^=\"close-button-\"]').click();",
        &result);
    // Ignore disconnected error, because it may be closed already.
    if (status.IsError() && status.code() != kDisconnected)
      return status;
  }

  // Wait until DevTools UI disconnects from the given web view.
  base::TimeTicks deadline =
      base::TimeTicks::Now() + base::TimeDelta::FromSeconds(20);
  while (base::TimeTicks::Now() < deadline) {
    status = GetWebViewsInfo(&views_info);
    if (status.IsError())
      return status;

    const WebViewInfo* view_info = views_info.GetForId(for_client_id);
    if (!view_info) {
      return Status(kDisconnected,
                    "DevTools client closed during closing UI debuggers");
    }
    if (view_info->debugger_url.size())
      return Status(kOk);

    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
  }
  return Status(kUnknownError, "failed to close UI debuggers");
}

bool DevToolsHttpClient::FetchUrlAndLog(const std::string& url,
                                        URLRequestContextGetter* getter,
                                        std::string* response) {
  VLOG(1) << "DevTools request: " << url;
  bool ok = FetchUrl(url, getter, response);
  if (ok) {
    VLOG(1) << "DevTools response: " << *response;
  } else {
    VLOG(1) << "DevTools request failed";
  }
  return ok;
}

namespace internal {

Status ParseWebViewsInfo(const std::string& data,
                         WebViewsInfo* views_info) {
  scoped_ptr<base::Value> value(base::JSONReader::Read(data));
  if (!value.get())
    return Status(kUnknownError, "DevTools returned invalid JSON");
  base::ListValue* list;
  if (!value->GetAsList(&list))
    return Status(kUnknownError, "DevTools did not return list");

  std::vector<WebViewInfo> temp_views_info;
  for (size_t i = 0; i < list->GetSize(); ++i) {
    base::DictionaryValue* info;
    if (!list->GetDictionary(i, &info))
      return Status(kUnknownError, "DevTools contains non-dictionary item");
    std::string id;
    if (!info->GetString("id", &id))
      return Status(kUnknownError, "DevTools did not include id");
    std::string type;
    if (!info->GetString("type", &type))
      return Status(kUnknownError, "DevTools did not include type");
    std::string url;
    if (!info->GetString("url", &url))
      return Status(kUnknownError, "DevTools did not include url");
    std::string debugger_url;
    info->GetString("webSocketDebuggerUrl", &debugger_url);
    if (type == "page")
      temp_views_info.push_back(
          WebViewInfo(id, debugger_url, url, WebViewInfo::kPage));
    else if (type == "other")
      temp_views_info.push_back(
          WebViewInfo(id, debugger_url, url, WebViewInfo::kOther));
    else
      return Status(kUnknownError, "DevTools returned unknown type:" + type);
  }
  *views_info = WebViewsInfo(temp_views_info);
  return Status(kOk);
}

Status ParseVersionInfo(const std::string& data,
                        std::string* version) {
  scoped_ptr<base::Value> value(base::JSONReader::Read(data));
  if (!value.get())
    return Status(kUnknownError, "version info not in JSON");
  base::DictionaryValue* dict;
  if (!value->GetAsDictionary(&dict))
    return Status(kUnknownError, "version info not a dictionary");
  if (!dict->GetString("Browser", version)) {
    return Status(
        kUnknownError,
        "Chrome version must be >= " + GetMinimumSupportedChromeVersion(),
        Status(kUnknownError, "version info doesn't include string 'Browser'"));
  }
  return Status(kOk);
}

}  // namespace internal
<commit_msg>[chromedriver] Fix a confusing error message.<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/chromedriver/chrome/devtools_http_client.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/json/json_reader.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
#include "chrome/test/chromedriver/chrome/log.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/version.h"
#include "chrome/test/chromedriver/chrome/web_view_impl.h"
#include "chrome/test/chromedriver/net/net_util.h"
#include "chrome/test/chromedriver/net/url_request_context_getter.h"

namespace {

Status FakeCloseFrontends() {
  return Status(kOk);
}

}  // namespace

WebViewInfo::WebViewInfo(const std::string& id,
                         const std::string& debugger_url,
                         const std::string& url,
                         Type type)
    : id(id), debugger_url(debugger_url), url(url), type(type) {}

WebViewInfo::~WebViewInfo() {}

bool WebViewInfo::IsFrontend() const {
  return url.find("chrome-devtools://") == 0u;
}

WebViewsInfo::WebViewsInfo() {}

WebViewsInfo::WebViewsInfo(const std::vector<WebViewInfo>& info)
    : views_info(info) {}

WebViewsInfo::~WebViewsInfo() {}

const WebViewInfo& WebViewsInfo::Get(int index) const {
  return views_info[index];
}

size_t WebViewsInfo::GetSize() const {
  return views_info.size();
}

const WebViewInfo* WebViewsInfo::GetForId(const std::string& id) const {
  for (size_t i = 0; i < views_info.size(); ++i) {
    if (views_info[i].id == id)
      return &views_info[i];
  }
  return NULL;
}

DevToolsHttpClient::DevToolsHttpClient(
    const NetAddress& address,
    scoped_refptr<URLRequestContextGetter> context_getter,
    const SyncWebSocketFactory& socket_factory)
    : context_getter_(context_getter),
      socket_factory_(socket_factory),
      server_url_("http://" + address.ToString()),
      web_socket_url_prefix_(base::StringPrintf(
          "ws://%s/devtools/page/", address.ToString().c_str())) {}

DevToolsHttpClient::~DevToolsHttpClient() {}

Status DevToolsHttpClient::Init(const base::TimeDelta& timeout) {
  base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
  std::string devtools_version;
  while (true) {
    Status status = GetVersion(&devtools_version);
    if (status.IsOk())
      break;
    if (status.code() != kChromeNotReachable ||
        base::TimeTicks::Now() > deadline) {
      return status;
    }
    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
  }

  int kToTBuildNo = 9999;
  if (devtools_version.empty()) {
    // Content Shell has an empty product version and a fake user agent.
    // There's no way to detect the actual version, so assume it is tip of tree.
    version_ = "content shell";
    build_no_ = kToTBuildNo;
    return Status(kOk);
  }
  if (devtools_version.find("Version/") == 0u) {
    version_ = "webview";
    build_no_ = kToTBuildNo;
    return Status(kOk);
  }
  std::string prefix = "Chrome/";
  if (devtools_version.find(prefix) != 0u) {
    return Status(kUnknownError,
                  "unrecognized Chrome version: " + devtools_version);
  }

  std::string stripped_version = devtools_version.substr(prefix.length());
  int temp_build_no;
  std::vector<std::string> version_parts;
  base::SplitString(stripped_version, '.', &version_parts);
  if (version_parts.size() != 4 ||
      !base::StringToInt(version_parts[2], &temp_build_no)) {
    return Status(kUnknownError,
                  "unrecognized Chrome version: " + devtools_version);
  }

  version_ = stripped_version;
  build_no_ = temp_build_no;
  return Status(kOk);
}

Status DevToolsHttpClient::GetWebViewsInfo(WebViewsInfo* views_info) {
  std::string data;
  if (!FetchUrlAndLog(server_url_ + "/json", context_getter_.get(), &data))
    return Status(kChromeNotReachable);

  return internal::ParseWebViewsInfo(data, views_info);
}

scoped_ptr<DevToolsClient> DevToolsHttpClient::CreateClient(
    const std::string& id) {
  return scoped_ptr<DevToolsClient>(new DevToolsClientImpl(
      socket_factory_,
      web_socket_url_prefix_ + id,
      id,
      base::Bind(
          &DevToolsHttpClient::CloseFrontends, base::Unretained(this), id)));
}

Status DevToolsHttpClient::CloseWebView(const std::string& id) {
  std::string data;
  if (!FetchUrlAndLog(
          server_url_ + "/json/close/" + id, context_getter_.get(), &data)) {
    return Status(kOk);  // Closing the last web view leads chrome to quit.
  }

  // Wait for the target window to be completely closed.
  base::TimeTicks deadline =
      base::TimeTicks::Now() + base::TimeDelta::FromSeconds(20);
  while (base::TimeTicks::Now() < deadline) {
    WebViewsInfo views_info;
    Status status = GetWebViewsInfo(&views_info);
    if (status.code() == kChromeNotReachable)
      return Status(kOk);
    if (status.IsError())
      return status;
    if (!views_info.GetForId(id))
      return Status(kOk);
    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
  }
  return Status(kUnknownError, "failed to close window in 20 seconds");
}

Status DevToolsHttpClient::ActivateWebView(const std::string& id) {
  std::string data;
  if (!FetchUrlAndLog(
          server_url_ + "/json/activate/" + id, context_getter_.get(), &data))
    return Status(kUnknownError, "cannot activate web view");
  return Status(kOk);
}

const std::string& DevToolsHttpClient::version() const {
  return version_;
}

int DevToolsHttpClient::build_no() const {
  return build_no_;
}

Status DevToolsHttpClient::GetVersion(std::string* version) {
  std::string data;
  if (!FetchUrlAndLog(
          server_url_ + "/json/version", context_getter_.get(), &data))
    return Status(kChromeNotReachable);

  return internal::ParseVersionInfo(data, version);
}

Status DevToolsHttpClient::CloseFrontends(const std::string& for_client_id) {
  WebViewsInfo views_info;
  Status status = GetWebViewsInfo(&views_info);
  if (status.IsError())
    return status;

  // Close frontends. Usually frontends are docked in the same page, although
  // some may be in tabs (undocked, chrome://inspect, the DevTools
  // discovery page, etc.). Tabs can be closed via the DevTools HTTP close
  // URL, but docked frontends can only be closed, by design, by connecting
  // to them and clicking the close button. Close the tab frontends first
  // in case one of them is debugging a docked frontend, which would prevent
  // the code from being able to connect to the docked one.
  std::list<std::string> tab_frontend_ids;
  std::list<std::string> docked_frontend_ids;
  for (size_t i = 0; i < views_info.GetSize(); ++i) {
    const WebViewInfo& view_info = views_info.Get(i);
    if (view_info.IsFrontend()) {
      if (view_info.type == WebViewInfo::kPage)
        tab_frontend_ids.push_back(view_info.id);
      else if (view_info.type == WebViewInfo::kOther)
        docked_frontend_ids.push_back(view_info.id);
      else
        return Status(kUnknownError, "unknown type of DevTools frontend");
    }
  }

  for (std::list<std::string>::const_iterator it = tab_frontend_ids.begin();
       it != tab_frontend_ids.end(); ++it) {
    status = CloseWebView(*it);
    if (status.IsError())
      return status;
  }

  for (std::list<std::string>::const_iterator it = docked_frontend_ids.begin();
       it != docked_frontend_ids.end(); ++it) {
    scoped_ptr<DevToolsClient> client(new DevToolsClientImpl(
        socket_factory_,
        web_socket_url_prefix_ + *it,
        *it,
        base::Bind(&FakeCloseFrontends)));
    scoped_ptr<WebViewImpl> web_view(
        new WebViewImpl(*it, build_no_, client.Pass()));

    status = web_view->ConnectIfNecessary();
    // Ignore disconnected error, because the debugger might have closed when
    // its container page was closed above.
    if (status.IsError() && status.code() != kDisconnected)
      return status;

    scoped_ptr<base::Value> result;
    status = web_view->EvaluateScript(
        std::string(),
        "document.querySelector('*[id^=\"close-button-\"]').click();",
        &result);
    // Ignore disconnected error, because it may be closed already.
    if (status.IsError() && status.code() != kDisconnected)
      return status;
  }

  // Wait until DevTools UI disconnects from the given web view.
  base::TimeTicks deadline =
      base::TimeTicks::Now() + base::TimeDelta::FromSeconds(20);
  while (base::TimeTicks::Now() < deadline) {
    status = GetWebViewsInfo(&views_info);
    if (status.IsError())
      return status;

    const WebViewInfo* view_info = views_info.GetForId(for_client_id);
    if (!view_info)
      return Status(kNoSuchWindow, "window was already closed");
    if (view_info->debugger_url.size())
      return Status(kOk);

    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50));
  }
  return Status(kUnknownError, "failed to close UI debuggers");
}

bool DevToolsHttpClient::FetchUrlAndLog(const std::string& url,
                                        URLRequestContextGetter* getter,
                                        std::string* response) {
  VLOG(1) << "DevTools request: " << url;
  bool ok = FetchUrl(url, getter, response);
  if (ok) {
    VLOG(1) << "DevTools response: " << *response;
  } else {
    VLOG(1) << "DevTools request failed";
  }
  return ok;
}

namespace internal {

Status ParseWebViewsInfo(const std::string& data,
                         WebViewsInfo* views_info) {
  scoped_ptr<base::Value> value(base::JSONReader::Read(data));
  if (!value.get())
    return Status(kUnknownError, "DevTools returned invalid JSON");
  base::ListValue* list;
  if (!value->GetAsList(&list))
    return Status(kUnknownError, "DevTools did not return list");

  std::vector<WebViewInfo> temp_views_info;
  for (size_t i = 0; i < list->GetSize(); ++i) {
    base::DictionaryValue* info;
    if (!list->GetDictionary(i, &info))
      return Status(kUnknownError, "DevTools contains non-dictionary item");
    std::string id;
    if (!info->GetString("id", &id))
      return Status(kUnknownError, "DevTools did not include id");
    std::string type;
    if (!info->GetString("type", &type))
      return Status(kUnknownError, "DevTools did not include type");
    std::string url;
    if (!info->GetString("url", &url))
      return Status(kUnknownError, "DevTools did not include url");
    std::string debugger_url;
    info->GetString("webSocketDebuggerUrl", &debugger_url);
    if (type == "page")
      temp_views_info.push_back(
          WebViewInfo(id, debugger_url, url, WebViewInfo::kPage));
    else if (type == "other")
      temp_views_info.push_back(
          WebViewInfo(id, debugger_url, url, WebViewInfo::kOther));
    else
      return Status(kUnknownError, "DevTools returned unknown type:" + type);
  }
  *views_info = WebViewsInfo(temp_views_info);
  return Status(kOk);
}

Status ParseVersionInfo(const std::string& data,
                        std::string* version) {
  scoped_ptr<base::Value> value(base::JSONReader::Read(data));
  if (!value.get())
    return Status(kUnknownError, "version info not in JSON");
  base::DictionaryValue* dict;
  if (!value->GetAsDictionary(&dict))
    return Status(kUnknownError, "version info not a dictionary");
  if (!dict->GetString("Browser", version)) {
    return Status(
        kUnknownError,
        "Chrome version must be >= " + GetMinimumSupportedChromeVersion(),
        Status(kUnknownError, "version info doesn't include string 'Browser'"));
  }
  return Status(kOk);
}

}  // namespace internal
<|endoftext|>


<commit_before>/*
 * master.cpp - master program for Team PI
 *
 * Wire(0) -> capTouch -> pixies -> SRF08s -> slave2 -> slave3
 * Wire1   -> slave1
 * by Brian Chen
 * (C) Team PI 2015
 */

#include <WProgram.h>
#include <i2c_t3.h>
#include <SPI.h>
#include <slaves.h>
#include <piCommon.h>
#include <PixyI2C.h> // modified for i2c_t3
#include <SRF08.h>
#include <fastTrig.h>
#include <PID.h>
#include <DebugUtils.h>

#define LED 13

#define RAMMING_SPEED 200
#define NORMAL_SPEED 130

uint32_t loopCount = 0;

/**********************************************************/
/*					     Slave1   						  */
/**********************************************************/
union float2bytes { float f; uint8_t b[sizeof(float)]; };
float2bytes f2b;
uint8_t inBuffer[22] = {0};
float bearing;
float bearing_offset;
int32_t bearing_int;

/**********************************************************/
/*                        Orbit                           */
/**********************************************************/
float orbit_l = 0.5;
float orbit_k = 1.0;
int16_t targetDir;
uint8_t targetVelocity;

/**********************************************************/
/*                    Face forwards                       */
/**********************************************************/
#define BEARING_KP 0.8
#define BEARING_KD 0

int32_t targetBearing = 0;
int32_t rotatationCorrection;

PID bearingPID (&bearing_int, &rotatationCorrection, &targetBearing,
	BEARING_KP, 0, BEARING_KD, -255, 255, 1000);

/**********************************************************/
/*                      Backspin                          */
/**********************************************************/
int16_t backspinSpeed = 0;

/**********************************************************/
/*                       Kicker                           */
/**********************************************************/
#define KICK_TIME 4000
#define KICK_DELAY 30
#define KICK_DURATION 90

#define KICK_SIG 21
#define KICK_ANA A3

bool kicking = false;
bool kickDelayComplete = false;
elapsedMillis capChargedTime = 0;

/**********************************************************/
/*					     Camera   						  */
/**********************************************************/
#define PIXY1_ADDRESS 0x54   // default i2c address

#define MIN_BLOCK_AREA   200

PixyI2C pixy1(PIXY1_ADDRESS);

int16_t blocks = 0;

int16_t goalAngle = 0;
int16_t goalAngle_rel_field = 0;
uint16_t goalArea = 0;

elapsedMillis lGoalDetectTime = 0;

bool goalDetected = false;

/**********************************************************/
/*					     Ultrasonics					  */
/**********************************************************/
#define SRF_BACK_ADDRESS  0x70  // 0xE0
#define SRF_RIGHT_ADDRESS 0x71  // 0xE2
#define SRF_LEFT_ADDRESS  0x72  // 0xE4

SRF08 srfBack(SRF_BACK_ADDRESS);
SRF08 srfRight(SRF_RIGHT_ADDRESS);
SRF08 srfLeft(SRF_LEFT_ADDRESS);

int16_t backDistance, rightDistance, leftDistance;

/**********************************************************/
/*					       TSOPS    					  */
/**********************************************************/

uint8_t tsopAngleByte;
int16_t tsopAngle;
int16_t tsopAngle_r_goal; // tsop angle relative to goal
uint8_t tsopStrength;
uint8_t ballDistance;

uint8_t tsopData[24] = {0};

/**********************************************************/
/*					       LASER    					  */
/**********************************************************/
#define LASER_SIG A1
#define LASER_REF 152

bool ballInZone = false;

void kick(){
	if (!kicking){
		// not yet kicking start kick
		kicking = true;
		capChargedTime = 0;
		Serial.print(millis());
		Serial.println("KICK_MOTORS");
	}
}

void checkEndKick(){
	if (kicking){
		if (!kickDelayComplete && capChargedTime > KICK_DELAY){
			kickDelayComplete = true;
			digitalWriteFast(KICK_SIG, HIGH);
			capChargedTime = 0; // now effectively discharge time
			Serial.print(millis());
			Serial.println("KICK");
		}
		else if (kickDelayComplete){
			// currently actually kicking
			if (capChargedTime >= KICK_DURATION){
				// end kick
				kicking = false;
				kickDelayComplete = false;
				digitalWriteFast(KICK_SIG, LOW);
				capChargedTime = 0;
				//Serial.print(analogRead(KICK_ANA));
				Serial.print(millis());
				Serial.println("END");
			}
		}
	}
	else{
		digitalWriteFast(KICK_SIG, LOW);
	}
}

void calibIMUOffset(){
	Slave1.requestPacket(SLAVE1_COMMANDS::CALIB_OFFSET);
	// for (int i = 0; i < 50; i++){
	// 	Slave1.requestPacket(SLAVE1_COMMANDS::REQUEST_STANDARD_PACKET);
	// 	Slave1.receivePacket(inBuffer, 7, true);

	// 	f2b.b[0] = inBuffer[2];
	// 	f2b.b[1] = inBuffer[3];
	// 	f2b.b[2] = inBuffer[4];
	// 	f2b.b[3] = inBuffer[5];
	// 	bearing_offset += -f2b.f;
	// 	delay(1);
	// }
	// bearing_offset /= 50;
}

void getSlave1Data(){
	Slave1.requestPacket(SLAVE1_COMMANDS::REQUEST_STANDARD_PACKET);
	Slave1.receivePacket(inBuffer, 7, true);

	f2b.b[0] = inBuffer[2];
	f2b.b[1] = inBuffer[3];
	f2b.b[2] = inBuffer[4];
	f2b.b[3] = inBuffer[5];

	bearing = f2b.f;
	bearing_int = (int32_t)(bearing);
	TOBEARING180(bearing_int);
	TOBEARING180(bearing);
}

void getSlave2Data(){
	Slave2.getTSOPAngleStrength(tsopAngle, tsopStrength);
	TOBEARING180(tsopAngle);
	tsopAngle_r_goal = tsopAngle - goalAngle;
	TOBEARING180(tsopAngle_r_goal);
}

void getGoalData(){
	goalArea = pixy1.blocks[0].width * pixy1.blocks[0].height;

	if (blocks > 0 && blocks < 1000
		&& goalArea > MIN_BLOCK_AREA
		&& abs(bearing) < 90
		){
		goalDetected = true;
		goalAngle = (pixy1.blocks[0].x - 160) * 75 / 360;
		goalAngle_rel_field = goalAngle + bearing_int;
		lGoalDetectTime = 0;
	}
	else if (lGoalDetectTime > 100){
		// hasn't seen goal for 100ms
		goalDetected = false;
		goalAngle = 0;
	}
}

void getBackspinSpeed(){
	if (!kicking){
		if (tsopStrength > 70){
			if (abs(targetDir) < 60){
				if (ballInZone){
					// we're going forwards and we have the ball
					// no need for too much spin
					backspinSpeed = 200;
				}
				else{
					// forwards but ball not here yet!
					backspinSpeed = 200;
				}
			}
			else{
				if (ballInZone){
					// we're not going forwards but we have the ball
					// best to spin a bit more as we need to guide the ball more
					backspinSpeed = 150;
				}
				else{
					// most common. Should only spin when ball is in front
					if (abs(tsopAngle) < 60){
						backspinSpeed = 120;
					}
					else{
						// no chance of getting ball any time soon
						backspinSpeed = 0;
					}
				}
			}
		}
		else{
			// no ball detected!
			backspinSpeed = 0;
		}
	}
	else{
		backspinSpeed = -255;
	}
}

void checkBallInZone(){
	if (analogRead(LASER_SIG) < LASER_REF
	 && abs(tsopAngle) < 30
	 && tsopStrength > 150){
		ballInZone = true;
	}
	else{
		ballInZone = false;
	}
}

void serialDebug(){
	Serial.printf("%d\t%d\t%d\t%.0f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
				  micros(),
				  goalAngle_rel_field,
				  goalArea,
				  bearing,
				  backDistance,
				  rightDistance,
				  leftDistance,
				  tsopAngle,
				  tsopStrength,
				  ballInZone,
				  targetDir,
				  targetVelocity,
				  rotatationCorrection);

	if(Serial.available()){
		char serialCommand = Serial.read();
		CLEARSERIAL(); // make sure you only read first byte and clear everything else
		if (serialCommand == 'i'){
			Serial.println("DEBUG INFO");
			Serial.printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s \n",
				  "micros()",
				  "goalAngle_rel_field",
				  "goalArea",
				  "bearing",
				  "backDistance",
				  "rightDistance",
				  "leftDistance",
				  "tsopAngle",
				  "tsopStrength",
				  "ballInZone",
				  "targetDir",
				  "targetVelocity",
				  "rotatationCorrection");
			Serial.println("PRESS ANY KEY TO CONTINUE");
			// wait for key
			while(!Serial.available());
			CLEARSERIAL();
		}
		else{
			Serial.println("UNKNOWN COMMAND");
		}
	}
}

int main(void){
	Serial.begin(115200);

	Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_400);

	SPI.setSCK(14);
	SPI.begin();

	Slave1.begin(115200);
	Slave2.begin();
	Slave3.begin();

	pinMode(LED, OUTPUT);
	pinMode(LASER_SIG, INPUT);

	pinMode(KICK_SIG, OUTPUT);
	pinMode(KICK_ANA, INPUT);

	digitalWrite(KICK_SIG, LOW);

	digitalWrite(LED, HIGH);

	delay(1000);

	calibIMUOffset();

	while(1){
		// save some time here as reading srf08's has seen to dramatically decrease performance
		switch(loopCount % 4){
			case 0: blocks = pixy1.getBlocks(); break;
			case 1: srfBack.getRangeIfCan(backDistance); break;
			case 2: srfRight.getRangeIfCan(rightDistance); break;
			case 3: srfLeft.getRangeIfCan(leftDistance); break;
		}

		/* orientation/imu */
		getSlave1Data();
		/* end orientation/imu */

		/* tsops */
		getSlave2Data();
		/* end tsops */

		/* goal detection */
		getGoalData();
		/* end goal detection */

		/* face forwards */
		if (goalDetected){
			targetBearing = goalAngle_rel_field;
		}
		else{
			targetBearing = 0;
		}

		bearingPID.update();
		/* end face forwards */

		/* ball in zone */
		checkBallInZone();
		/* end ball in zone */

		/*movement control*/

		targetVelocity = NORMAL_SPEED;

		orbit_k = 1;

		if (tsopStrength > 156){
			orbit_k = 1.1;
		}
		else if (tsopStrength > 150){
			orbit_k = 1.05;
		}
		else if (tsopStrength > 140){
			orbit_k = 1.0;
		}
		else if (tsopStrength > 130){
			orbit_k = 1.0;
		}
		else if (tsopStrength > 120){
			orbit_k = 1;
		}
		else if (tsopStrength > 100){
			orbit_k = 1;
		}
		else if (tsopStrength > 70){
			orbit_k = 1;
		}
		else{
			targetVelocity = 0;
		}

		// if (tsopAngle > 90){
		// 	targetDir = (orbit_k * 180 - 90 + tsopAngle);
		// }
		// else if (tsopAngle < -90){
		// 	targetDir = (orbit_k * -180 + 90 + tsopAngle);
		// }
		// else{
			targetDir = orbit_k * (270 - abs(tsopAngle)) / 90 * tsopAngle;
		// }
		goalDetected = true;
		goalAngle = 0;
		if (ballInZone && goalDetected && abs(goalAngle) < 10){
			// GO!
			targetDir = goalAngle;
			targetVelocity = RAMMING_SPEED;
			// kick!
			if (capChargedTime > KICK_TIME){
				kick();
			}
		}
		checkEndKick();

		/* end movement control */

		/* backspin control */
		getBackspinSpeed();
		/* end backspin control */

		if (targetDir < 0) targetDir += 360;
		targetDir = targetDir * 255/360;

		// Slave3.moveRobot((uint8_t)targetDir, targetVelocity, rotatationCorrection);
		Slave3.moveMotorE(backspinSpeed);

		/* debugging */
		serialDebug();
		/* end debugging */

		loopCount++;  // update loop count
	}
}<commit_msg>increased min block area to reaonsable size<commit_after>/*
 * master.cpp - master program for Team PI
 *
 * Wire(0) -> capTouch -> pixies -> SRF08s -> slave2 -> slave3
 * Wire1   -> slave1
 * by Brian Chen
 * (C) Team PI 2015
 */

#include <WProgram.h>
#include <i2c_t3.h>
#include <SPI.h>
#include <slaves.h>
#include <piCommon.h>
#include <PixyI2C.h> // modified for i2c_t3
#include <SRF08.h>
#include <fastTrig.h>
#include <PID.h>
#include <DebugUtils.h>

#define LED 13

#define RAMMING_SPEED 200
#define NORMAL_SPEED 130

uint32_t loopCount = 0;

/**********************************************************/
/*					     Slave1   						  */
/**********************************************************/
union float2bytes { float f; uint8_t b[sizeof(float)]; };
float2bytes f2b;
uint8_t inBuffer[22] = {0};
float bearing;
float bearing_offset;
int32_t bearing_int;

/**********************************************************/
/*                        Orbit                           */
/**********************************************************/
float orbit_l = 0.5;
float orbit_k = 1.0;
int16_t targetDir;
uint8_t targetVelocity;

/**********************************************************/
/*                    Face forwards                       */
/**********************************************************/
#define BEARING_KP 0.8
#define BEARING_KD 0

int32_t targetBearing = 0;
int32_t rotatationCorrection;

PID bearingPID (&bearing_int, &rotatationCorrection, &targetBearing,
	BEARING_KP, 0, BEARING_KD, -255, 255, 1000);

/**********************************************************/
/*                      Backspin                          */
/**********************************************************/
int16_t backspinSpeed = 0;

/**********************************************************/
/*                       Kicker                           */
/**********************************************************/
#define KICK_TIME 4000
#define KICK_DELAY 30
#define KICK_DURATION 90

#define KICK_SIG 21
#define KICK_ANA A3

bool kicking = false;
bool kickDelayComplete = false;
elapsedMillis capChargedTime = 0;

/**********************************************************/
/*					     Camera   						  */
/**********************************************************/
#define PIXY1_ADDRESS 0x54   // default i2c address

#define MIN_BLOCK_AREA   1500

PixyI2C pixy1(PIXY1_ADDRESS);

int16_t blocks = 0;

int16_t goalAngle = 0;
int16_t goalAngle_rel_field = 0;
uint16_t goalArea = 0;

elapsedMillis lGoalDetectTime = 0;

bool goalDetected = false;

/**********************************************************/
/*					     Ultrasonics					  */
/**********************************************************/
#define SRF_BACK_ADDRESS  0x70  // 0xE0
#define SRF_RIGHT_ADDRESS 0x71  // 0xE2
#define SRF_LEFT_ADDRESS  0x72  // 0xE4

SRF08 srfBack(SRF_BACK_ADDRESS);
SRF08 srfRight(SRF_RIGHT_ADDRESS);
SRF08 srfLeft(SRF_LEFT_ADDRESS);

int16_t backDistance, rightDistance, leftDistance;

/**********************************************************/
/*					       TSOPS    					  */
/**********************************************************/

uint8_t tsopAngleByte;
int16_t tsopAngle;
int16_t tsopAngle_r_goal; // tsop angle relative to goal
uint8_t tsopStrength;
uint8_t ballDistance;

uint8_t tsopData[24] = {0};

/**********************************************************/
/*					       LASER    					  */
/**********************************************************/
#define LASER_SIG A1
#define LASER_REF 152

bool ballInZone = false;

void kick(){
	if (!kicking){
		// not yet kicking start kick
		kicking = true;
		capChargedTime = 0;
		Serial.print(millis());
		Serial.println("KICK_MOTORS");
	}
}

void checkEndKick(){
	if (kicking){
		if (!kickDelayComplete && capChargedTime > KICK_DELAY){
			kickDelayComplete = true;
			digitalWriteFast(KICK_SIG, HIGH);
			capChargedTime = 0; // now effectively discharge time
			Serial.print(millis());
			Serial.println("KICK");
		}
		else if (kickDelayComplete){
			// currently actually kicking
			if (capChargedTime >= KICK_DURATION){
				// end kick
				kicking = false;
				kickDelayComplete = false;
				digitalWriteFast(KICK_SIG, LOW);
				capChargedTime = 0;
				//Serial.print(analogRead(KICK_ANA));
				Serial.print(millis());
				Serial.println("END");
			}
		}
	}
	else{
		digitalWriteFast(KICK_SIG, LOW);
	}
}

void calibIMUOffset(){
	Slave1.requestPacket(SLAVE1_COMMANDS::CALIB_OFFSET);
	// for (int i = 0; i < 50; i++){
	// 	Slave1.requestPacket(SLAVE1_COMMANDS::REQUEST_STANDARD_PACKET);
	// 	Slave1.receivePacket(inBuffer, 7, true);

	// 	f2b.b[0] = inBuffer[2];
	// 	f2b.b[1] = inBuffer[3];
	// 	f2b.b[2] = inBuffer[4];
	// 	f2b.b[3] = inBuffer[5];
	// 	bearing_offset += -f2b.f;
	// 	delay(1);
	// }
	// bearing_offset /= 50;
}

void getSlave1Data(){
	Slave1.requestPacket(SLAVE1_COMMANDS::REQUEST_STANDARD_PACKET);
	Slave1.receivePacket(inBuffer, 7, true);

	f2b.b[0] = inBuffer[2];
	f2b.b[1] = inBuffer[3];
	f2b.b[2] = inBuffer[4];
	f2b.b[3] = inBuffer[5];

	bearing = f2b.f;
	bearing_int = (int32_t)(bearing);
	TOBEARING180(bearing_int);
	TOBEARING180(bearing);
}

void getSlave2Data(){
	Slave2.getTSOPAngleStrength(tsopAngle, tsopStrength);
	TOBEARING180(tsopAngle);
	tsopAngle_r_goal = tsopAngle - goalAngle;
	TOBEARING180(tsopAngle_r_goal);
}

void getGoalData(){
	goalArea = pixy1.blocks[0].width * pixy1.blocks[0].height;

	if (blocks > 0 && blocks < 1000
		&& goalArea > MIN_BLOCK_AREA
		&& abs(bearing) < 90
		){
		goalDetected = true;
		goalAngle = (pixy1.blocks[0].x - 160) * 75 / 360;
		goalAngle_rel_field = goalAngle + bearing_int;
		lGoalDetectTime = 0;
	}
	else if (lGoalDetectTime > 100){
		// hasn't seen goal for 100ms
		goalDetected = false;
		goalAngle = 0;
	}
}

void getBackspinSpeed(){
	if (!kicking){
		if (tsopStrength > 70){
			if (abs(targetDir) < 60){
				if (ballInZone){
					// we're going forwards and we have the ball
					// no need for too much spin
					backspinSpeed = 200;
				}
				else{
					// forwards but ball not here yet!
					backspinSpeed = 200;
				}
			}
			else{
				if (ballInZone){
					// we're not going forwards but we have the ball
					// best to spin a bit more as we need to guide the ball more
					backspinSpeed = 150;
				}
				else{
					// most common. Should only spin when ball is in front
					if (abs(tsopAngle) < 60){
						backspinSpeed = 120;
					}
					else{
						// no chance of getting ball any time soon
						backspinSpeed = 0;
					}
				}
			}
		}
		else{
			// no ball detected!
			backspinSpeed = 0;
		}
	}
	else{
		backspinSpeed = -255;
	}
}

void checkBallInZone(){
	if (analogRead(LASER_SIG) < LASER_REF
	 && abs(tsopAngle) < 30
	 && tsopStrength > 150){
		ballInZone = true;
	}
	else{
		ballInZone = false;
	}
}

void serialDebug(){
	Serial.printf("%d\t%d\t%d\t%.0f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
				  micros(),
				  goalAngle_rel_field,
				  goalArea,
				  bearing,
				  backDistance,
				  rightDistance,
				  leftDistance,
				  tsopAngle,
				  tsopStrength,
				  ballInZone,
				  targetDir,
				  targetVelocity,
				  rotatationCorrection);

	if(Serial.available()){
		char serialCommand = Serial.read();
		CLEARSERIAL(); // make sure you only read first byte and clear everything else
		if (serialCommand == 'i'){
			Serial.println("DEBUG INFO");
			Serial.printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s \n",
				  "micros()",
				  "goalAngle_rel_field",
				  "goalArea",
				  "bearing",
				  "backDistance",
				  "rightDistance",
				  "leftDistance",
				  "tsopAngle",
				  "tsopStrength",
				  "ballInZone",
				  "targetDir",
				  "targetVelocity",
				  "rotatationCorrection");
			Serial.println("PRESS ANY KEY TO CONTINUE");
			// wait for key
			while(!Serial.available());
			CLEARSERIAL();
		}
		else{
			Serial.println("UNKNOWN COMMAND");
		}
	}
}

int main(void){
	Serial.begin(115200);

	Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_400);

	SPI.setSCK(14);
	SPI.begin();

	Slave1.begin(115200);
	Slave2.begin();
	Slave3.begin();

	pinMode(LED, OUTPUT);
	pinMode(LASER_SIG, INPUT);

	pinMode(KICK_SIG, OUTPUT);
	pinMode(KICK_ANA, INPUT);

	digitalWrite(KICK_SIG, LOW);

	digitalWrite(LED, HIGH);

	delay(1000);

	calibIMUOffset();

	while(1){
		// save some time here as reading srf08's has seen to dramatically decrease performance
		switch(loopCount % 4){
			case 0: blocks = pixy1.getBlocks(); break;
			case 1: srfBack.getRangeIfCan(backDistance); break;
			case 2: srfRight.getRangeIfCan(rightDistance); break;
			case 3: srfLeft.getRangeIfCan(leftDistance); break;
		}

		/* orientation/imu */
		getSlave1Data();
		/* end orientation/imu */

		/* tsops */
		getSlave2Data();
		/* end tsops */

		/* goal detection */
		getGoalData();
		/* end goal detection */

		/* face forwards */
		if (goalDetected){
			targetBearing = goalAngle_rel_field;
		}
		else{
			targetBearing = 0;
		}

		bearingPID.update();
		/* end face forwards */

		/* ball in zone */
		checkBallInZone();
		/* end ball in zone */

		/*movement control*/

		targetVelocity = NORMAL_SPEED;

		orbit_k = 1;

		if (tsopStrength > 156){
			orbit_k = 1.1;
		}
		else if (tsopStrength > 150){
			orbit_k = 1.05;
		}
		else if (tsopStrength > 140){
			orbit_k = 1.0;
		}
		else if (tsopStrength > 130){
			orbit_k = 1.0;
		}
		else if (tsopStrength > 120){
			orbit_k = 1;
		}
		else if (tsopStrength > 100){
			orbit_k = 1;
		}
		else if (tsopStrength > 70){
			orbit_k = 1;
		}
		else{
			targetVelocity = 0;
		}

		// if (tsopAngle > 90){
		// 	targetDir = (orbit_k * 180 - 90 + tsopAngle);
		// }
		// else if (tsopAngle < -90){
		// 	targetDir = (orbit_k * -180 + 90 + tsopAngle);
		// }
		// else{
			targetDir = orbit_k * (270 - abs(tsopAngle)) / 90 * tsopAngle;
		// }
		goalDetected = true;
		goalAngle = 0;
		if (ballInZone && goalDetected && abs(goalAngle) < 10){
			// GO!
			targetDir = goalAngle;
			targetVelocity = RAMMING_SPEED;
			// kick!
			if (capChargedTime > KICK_TIME){
				kick();
			}
		}
		checkEndKick();

		/* end movement control */

		/* backspin control */
		getBackspinSpeed();
		/* end backspin control */

		if (targetDir < 0) targetDir += 360;
		targetDir = targetDir * 255/360;

		// Slave3.moveRobot((uint8_t)targetDir, targetVelocity, rotatationCorrection);
		Slave3.moveMotorE(backspinSpeed);

		/* debugging */
		serialDebug();
		/* end debugging */

		loopCount++;  // update loop count
	}
}<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include <cstdlib>
#include <ctime>

#include <iostream>
#include <fstream>

#include <itksys/SystemTools.hxx>
#include "mitkPixelType.h"
#include "itkImageRegionIterator.h"
#include "itkImageFileReader.h"
#include <mitkIOUtil.h>

template< class D, class T >
mitk::TeemDiffusionTensor3DReconstructionImageFilter<D,T>
::TeemDiffusionTensor3DReconstructionImageFilter():
m_EstimateErrorImage(false),m_Sigma(-19191919),
m_EstimationMethod(TeemTensorEstimationMethodsLLS),
m_NumIterations(1),m_ConfidenceThreshold(-19191919.0),
m_ConfidenceFuzzyness(0.0),m_MinPlausibleValue(1.0)
{
}

template< class D, class T >
mitk::TeemDiffusionTensor3DReconstructionImageFilter<D,T>
::~TeemDiffusionTensor3DReconstructionImageFilter()
{
}

void file_replace(std::string filename, std::string what, std::string with)
{
  ofstream myfile2;

  std::locale C("C");
  std::locale originalLocale2 = myfile2.getloc();
  myfile2.imbue(C);

  char filename2[512];
  sprintf(filename2, "%s2",filename.c_str());
  myfile2.open (filename2);

  std::string line;
  ifstream myfile (filename.c_str());

  std::locale originalLocale = myfile.getloc();
  myfile.imbue(C);

  if (myfile.is_open())
  {
    while (! myfile.eof() )
    {
      getline (myfile,line);
      itksys::SystemTools::ReplaceString(line,what.c_str(),with.c_str());
      myfile2 << line << std::endl;
    }
    myfile.close();
  }
  myfile2.close();
  itksys::SystemTools::RemoveFile(filename.c_str());
  rename(filename2,filename.c_str());

  myfile.imbue( originalLocale );
  myfile2.imbue( originalLocale2 );
}

// do the work
template< class D, class T >
void
mitk::TeemDiffusionTensor3DReconstructionImageFilter<D,T>
::Update()
{

  // save input image to nrrd file in temp-folder
  char filename[512];
  srand((unsigned)time(0));
  int random_integer = rand();
  sprintf( filename, "dwi_%d.nhdr",random_integer);

  try
  {
    mitk::IOUtil::Save(m_Input, filename.c_str());
  }
  catch (itk::ExceptionObject e)
  {
    std::cout << e << std::endl;
  }

  file_replace(filename,"vector","list");

  // build up correct command from input params
  char command[4096];
  sprintf( command, "tend estim -i %s -B kvp -o tensors_%d.nhdr -knownB0 true",
    filename, random_integer);

  //m_DiffusionImages;
  if(m_EstimateErrorImage)
  {
    sprintf( command, "%s -ee error_image_%d.nhdr", command, random_integer);
  }

  if(m_Sigma != -19191919)
  {
    sprintf( command, "%s -sigma %f", command, m_Sigma);
  }

  switch(m_EstimationMethod)
  {
  case TeemTensorEstimationMethodsLLS:
    sprintf( command, "%s -est lls", command);
    break;
  case TeemTensorEstimationMethodsMLE:
    sprintf( command, "%s -est mle", command);
    break;
  case TeemTensorEstimationMethodsNLS:
    sprintf( command, "%s -est nls", command);
    break;
  case TeemTensorEstimationMethodsWLS:
    sprintf( command, "%s -est wls", command);
    break;
  }

  sprintf( command, "%s -wlsi %d", command, m_NumIterations);

  if(m_ConfidenceThreshold != -19191919.0)
  {
    sprintf( command, "%s -t %f", command, m_ConfidenceThreshold);
  }

  sprintf( command, "%s -soft %f", command, m_ConfidenceFuzzyness);
  sprintf( command, "%s -mv %f", command, m_MinPlausibleValue);

  // call tend estim command
  std::cout << "Calling <" << command << ">" << std::endl;
  int success = system(command);
  if(!success)
  {
    MITK_ERROR << "system command could not be called!";
  }

  remove(filename);
  sprintf( filename, "dwi_%d.raw", random_integer);
  remove(filename);

  // change kind from tensor to vector
  sprintf( filename, "tensors_%d.nhdr", random_integer);
  file_replace(filename,"3D-masked-symmetric-matrix","vector");

  // read result as mitk::Image and provide it in m_Output
  typedef itk::ImageFileReader<VectorImageType> FileReaderType;
  typename FileReaderType::Pointer reader = FileReaderType::New();
  reader->SetFileName(filename);
  reader->Update();
  typename VectorImageType::Pointer vecImage = reader->GetOutput();

  remove(filename);
  sprintf( filename, "tensors_%d.raw", random_integer);
  remove(filename);

  typename ItkTensorImageType::Pointer itkTensorImage = ItkTensorImageType::New();
  itkTensorImage->SetSpacing( vecImage->GetSpacing() );   // Set the image spacing
  itkTensorImage->SetOrigin( vecImage->GetOrigin() );     // Set the image origin
  itkTensorImage->SetDirection( vecImage->GetDirection() );  // Set the image direction
  itkTensorImage->SetLargestPossibleRegion( vecImage->GetLargestPossibleRegion() );
  itkTensorImage->SetBufferedRegion( vecImage->GetLargestPossibleRegion() );
  itkTensorImage->SetRequestedRegion( vecImage->GetLargestPossibleRegion() );
  itkTensorImage->Allocate();

  itk::ImageRegionIterator<VectorImageType> it(vecImage,
    vecImage->GetLargestPossibleRegion());

  itk::ImageRegionIterator<ItkTensorImageType> it2(itkTensorImage,
    itkTensorImage->GetLargestPossibleRegion());
  it2 = it2.Begin();

  //#pragma omp parallel private (it)
  {
    for(it=it.Begin();!it.IsAtEnd(); ++it, ++it2)
    {
      //#pragma omp single nowait
      {
        VectorType vec = it.Get();
        TensorType tensor;
        for(int i=1;i<7;i++)
          tensor[i-1] = vec[i] * vec[0];
        it2.Set( tensor );
      }
    } // end for
  } // end ompparallel

  m_OutputItk = mitk::TensorImage::New();
  m_OutputItk->InitializeByItk(itkTensorImage.GetPointer());
  m_OutputItk->SetVolume( itkTensorImage->GetBufferPointer() );

  // in case: read resulting error-image and provide it in m_ErrorImage
  if(m_EstimateErrorImage)
  {
    // open error image here
  }

}

<commit_msg>COMP: variable is already a c string<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include <cstdlib>
#include <ctime>

#include <iostream>
#include <fstream>

#include <itksys/SystemTools.hxx>
#include "mitkPixelType.h"
#include "itkImageRegionIterator.h"
#include "itkImageFileReader.h"
#include <mitkIOUtil.h>

template< class D, class T >
mitk::TeemDiffusionTensor3DReconstructionImageFilter<D,T>
::TeemDiffusionTensor3DReconstructionImageFilter():
m_EstimateErrorImage(false),m_Sigma(-19191919),
m_EstimationMethod(TeemTensorEstimationMethodsLLS),
m_NumIterations(1),m_ConfidenceThreshold(-19191919.0),
m_ConfidenceFuzzyness(0.0),m_MinPlausibleValue(1.0)
{
}

template< class D, class T >
mitk::TeemDiffusionTensor3DReconstructionImageFilter<D,T>
::~TeemDiffusionTensor3DReconstructionImageFilter()
{
}

void file_replace(std::string filename, std::string what, std::string with)
{
  ofstream myfile2;

  std::locale C("C");
  std::locale originalLocale2 = myfile2.getloc();
  myfile2.imbue(C);

  char filename2[512];
  sprintf(filename2, "%s2",filename.c_str());
  myfile2.open (filename2);

  std::string line;
  ifstream myfile (filename.c_str());

  std::locale originalLocale = myfile.getloc();
  myfile.imbue(C);

  if (myfile.is_open())
  {
    while (! myfile.eof() )
    {
      getline (myfile,line);
      itksys::SystemTools::ReplaceString(line,what.c_str(),with.c_str());
      myfile2 << line << std::endl;
    }
    myfile.close();
  }
  myfile2.close();
  itksys::SystemTools::RemoveFile(filename.c_str());
  rename(filename2,filename.c_str());

  myfile.imbue( originalLocale );
  myfile2.imbue( originalLocale2 );
}

// do the work
template< class D, class T >
void
mitk::TeemDiffusionTensor3DReconstructionImageFilter<D,T>
::Update()
{

  // save input image to nrrd file in temp-folder
  char filename[512];
  srand((unsigned)time(0));
  int random_integer = rand();
  sprintf( filename, "dwi_%d.nhdr",random_integer);

  try
  {
    mitk::IOUtil::Save(m_Input, filename);
  }
  catch (itk::ExceptionObject e)
  {
    std::cout << e << std::endl;
  }

  file_replace(filename,"vector","list");

  // build up correct command from input params
  char command[4096];
  sprintf( command, "tend estim -i %s -B kvp -o tensors_%d.nhdr -knownB0 true",
    filename, random_integer);

  //m_DiffusionImages;
  if(m_EstimateErrorImage)
  {
    sprintf( command, "%s -ee error_image_%d.nhdr", command, random_integer);
  }

  if(m_Sigma != -19191919)
  {
    sprintf( command, "%s -sigma %f", command, m_Sigma);
  }

  switch(m_EstimationMethod)
  {
  case TeemTensorEstimationMethodsLLS:
    sprintf( command, "%s -est lls", command);
    break;
  case TeemTensorEstimationMethodsMLE:
    sprintf( command, "%s -est mle", command);
    break;
  case TeemTensorEstimationMethodsNLS:
    sprintf( command, "%s -est nls", command);
    break;
  case TeemTensorEstimationMethodsWLS:
    sprintf( command, "%s -est wls", command);
    break;
  }

  sprintf( command, "%s -wlsi %d", command, m_NumIterations);

  if(m_ConfidenceThreshold != -19191919.0)
  {
    sprintf( command, "%s -t %f", command, m_ConfidenceThreshold);
  }

  sprintf( command, "%s -soft %f", command, m_ConfidenceFuzzyness);
  sprintf( command, "%s -mv %f", command, m_MinPlausibleValue);

  // call tend estim command
  std::cout << "Calling <" << command << ">" << std::endl;
  int success = system(command);
  if(!success)
  {
    MITK_ERROR << "system command could not be called!";
  }

  remove(filename);
  sprintf( filename, "dwi_%d.raw", random_integer);
  remove(filename);

  // change kind from tensor to vector
  sprintf( filename, "tensors_%d.nhdr", random_integer);
  file_replace(filename,"3D-masked-symmetric-matrix","vector");

  // read result as mitk::Image and provide it in m_Output
  typedef itk::ImageFileReader<VectorImageType> FileReaderType;
  typename FileReaderType::Pointer reader = FileReaderType::New();
  reader->SetFileName(filename);
  reader->Update();
  typename VectorImageType::Pointer vecImage = reader->GetOutput();

  remove(filename);
  sprintf( filename, "tensors_%d.raw", random_integer);
  remove(filename);

  typename ItkTensorImageType::Pointer itkTensorImage = ItkTensorImageType::New();
  itkTensorImage->SetSpacing( vecImage->GetSpacing() );   // Set the image spacing
  itkTensorImage->SetOrigin( vecImage->GetOrigin() );     // Set the image origin
  itkTensorImage->SetDirection( vecImage->GetDirection() );  // Set the image direction
  itkTensorImage->SetLargestPossibleRegion( vecImage->GetLargestPossibleRegion() );
  itkTensorImage->SetBufferedRegion( vecImage->GetLargestPossibleRegion() );
  itkTensorImage->SetRequestedRegion( vecImage->GetLargestPossibleRegion() );
  itkTensorImage->Allocate();

  itk::ImageRegionIterator<VectorImageType> it(vecImage,
    vecImage->GetLargestPossibleRegion());

  itk::ImageRegionIterator<ItkTensorImageType> it2(itkTensorImage,
    itkTensorImage->GetLargestPossibleRegion());
  it2 = it2.Begin();

  //#pragma omp parallel private (it)
  {
    for(it=it.Begin();!it.IsAtEnd(); ++it, ++it2)
    {
      //#pragma omp single nowait
      {
        VectorType vec = it.Get();
        TensorType tensor;
        for(int i=1;i<7;i++)
          tensor[i-1] = vec[i] * vec[0];
        it2.Set( tensor );
      }
    } // end for
  } // end ompparallel

  m_OutputItk = mitk::TensorImage::New();
  m_OutputItk->InitializeByItk(itkTensorImage.GetPointer());
  m_OutputItk->SetVolume( itkTensorImage->GetBufferPointer() );

  // in case: read resulting error-image and provide it in m_ErrorImage
  if(m_EstimateErrorImage)
  {
    // open error image here
  }

}

<|endoftext|>


<commit_before>//@ {"targets":[{"name":"serializer.hpp","type":"include"}]}

#ifndef TEMPLE_SERIALIZER_HPP
#define TEMPLE_SERIALIZER_HPP

#include "item.hpp"
#include "treenode.hpp"
#include <stack>

namespace Temple
	{
	namespace
		{
		template<class Callback>
		class VisitorBase
			{
			public:
				virtual bool atEnd() const noexcept=0;
				virtual void advance() noexcept=0;
				virtual void itemProcess(Callback& cb) const=0;
				virtual ~VisitorBase()=default;
				char terminator() const noexcept
					{return m_terminator;}
			protected:
				explicit VisitorBase(char term) noexcept:
					m_terminator(term)
					{}

			private:
				char m_terminator;
			};

		template<class Callback,class Container>
		class Visitor:public VisitorBase<Callback>
			{
			public:
				explicit Visitor(Container&&)=delete;
				explicit Visitor(const Container& container,char term):
					 VisitorBase<Callback>(term)
					,m_begin(container.begin())
					,m_current(container.begin())
					,m_end(container.end())
					{}

				bool atEnd() const noexcept
					{return m_current==m_end;}

				bool atBegin() const noexcept
					{return m_current==m_begin;}

				void advance() noexcept
					{++m_current;}

				void itemProcess(Callback& cb) const
					{cb(*m_current,*this);}

				static auto create(const Container& cnt,char term)
					{return std::unique_ptr<VisitorBase<Callback>>(new Visitor(cnt,term));}

			private:
				typename Container::const_iterator m_begin;
				typename Container::const_iterator m_current;
				typename Container::const_iterator m_end;
			};

		template<class Cstr,class Sink>
		static void write(Cstr src,Sink& sink)
			{
			while(true)
				{
				auto ch_in=*src;
				if(ch_in=='\0')
					{return;}
				if(ch_in=='\\' || ch_in=='\"')
					{putc('\\',sink);}
				putc(ch_in,sink);
				++src;
				}
			}

		template<class StorageModel,class Sink>
		class Acceptor
			{
			public:
				using MapType=typename StorageModel::template MapType< std::unique_ptr< ItemBase<StorageModel> > > ;
				using CompoundArray=typename StorageModel::template ArrayType<MapType>;

				using VisitorArray=Visitor<Acceptor,CompoundArray>;
				using VisitorMap=Visitor<Acceptor,MapType>;

				explicit Acceptor(ItemBase<StorageModel>&&)=delete;

				explicit Acceptor(const ItemBase<StorageModel>& root,Sink& sink):r_sink(sink)
					{
					if(root.array())
						{m_stack.push(VisitorArray::create(root.template value<CompoundArray>(),']') );}
					else
						{m_stack.push(VisitorMap::create(root.template value<MapType>(),'}'));}
					}

				void run()
					{
					while(!m_stack.empty())
						{
						auto& visitor=m_stack.top();
						if(visitor->atEnd())
							{
							putc(visitor->terminator(),r_sink);
							m_stack.pop();
							}
						else
							{
							visitor->itemProcess(*this);
							visitor->advance();
							}
						}
					}

				void operator()(const MapType& node_current,const VisitorArray& visitor)
					{
					putc(visitor.atBegin()?'[':',',r_sink);
					m_stack.push(VisitorMap::create(node_current,'}'));
					}

				void operator()(const typename MapType::value_type& node_current,const VisitorMap& visitor)
					{
					putc(visitor.atBegin()?'{':',',r_sink);
					putc('"',r_sink);
					write(node_current.first.c_str(),r_sink);
					putc('"',r_sink);
					}

			private:
				Sink& r_sink;
				std::stack< std::unique_ptr< VisitorBase<Acceptor> > > m_stack;
			};
		}

	template<class StorageModel,class Sink>
	void temple_store(const ItemBase<StorageModel>& root,Sink& sink)
		{Acceptor<StorageModel,Sink>(root,sink).run();}
	}

#endif
<commit_msg>Fixed empty objects<commit_after>//@ {"targets":[{"name":"serializer.hpp","type":"include"}]}

#ifndef TEMPLE_SERIALIZER_HPP
#define TEMPLE_SERIALIZER_HPP

#include "item.hpp"
#include "treenode.hpp"
#include <stack>

namespace Temple
	{
	namespace
		{
		template<class Callback>
		class VisitorBase
			{
			public:
				virtual bool atEnd() const noexcept=0;
				virtual void advance() noexcept=0;
				virtual void itemProcess(Callback& cb) const=0;
				virtual ~VisitorBase()=default;
				char terminator() const noexcept
					{return m_terminator;}
			protected:
				explicit VisitorBase(char term) noexcept:
					m_terminator(term)
					{}

			private:
				char m_terminator;
			};

		template<class Callback,class Container>
		class Visitor:public VisitorBase<Callback>
			{
			public:
				explicit Visitor(Container&&)=delete;
				explicit Visitor(const Container& container,char term):
					 VisitorBase<Callback>(term)
					,m_begin(container.begin())
					,m_current(container.begin())
					,m_end(container.end())
					{}

				bool atEnd() const noexcept
					{return m_current==m_end;}

				bool atBegin() const noexcept
					{return m_current==m_begin;}

				void advance() noexcept
					{++m_current;}

				void itemProcess(Callback& cb) const
					{cb(*m_current,*this);}

				static auto create(const Container& cnt,char term)
					{return std::unique_ptr<VisitorBase<Callback>>(new Visitor(cnt,term));}

			private:
				typename Container::const_iterator m_begin;
				typename Container::const_iterator m_current;
				typename Container::const_iterator m_end;
			};

		template<class Cstr,class Sink>
		static void write(Cstr src,Sink& sink)
			{
			while(true)
				{
				auto ch_in=*src;
				if(ch_in=='\0')
					{return;}
				if(ch_in=='\\' || ch_in=='\"')
					{putc('\\',sink);}
				putc(ch_in,sink);
				++src;
				}
			}

		template<class StorageModel,class Sink>
		class Acceptor
			{
			public:
				using MapType=typename StorageModel::template MapType< std::unique_ptr< ItemBase<StorageModel> > > ;
				using CompoundArray=typename StorageModel::template ArrayType<MapType>;

				using VisitorArray=Visitor<Acceptor,CompoundArray>;
				using VisitorMap=Visitor<Acceptor,MapType>;

				explicit Acceptor(ItemBase<StorageModel>&&)=delete;

				explicit Acceptor(const ItemBase<StorageModel>& root,Sink& sink):r_sink(sink)
					{
					if(root.array())
						{m_stack.push(VisitorArray::create(root.template value<CompoundArray>(),']') );}
					else
						{m_stack.push(VisitorMap::create(root.template value<MapType>(),'}'));}
					}

				void run()
					{
					while(!m_stack.empty())
						{
						auto& visitor=m_stack.top();
						if(visitor->atEnd())
							{
							putc(visitor->terminator(),r_sink);
							m_stack.pop();
							}
						else
							{
							visitor->itemProcess(*this);
							visitor->advance();
							}
						}
					}

				void operator()(const MapType& node_current,const VisitorArray& visitor)
					{
					putc(visitor.atBegin()?'[':',',r_sink);
					m_stack.push(VisitorMap::create(node_current,'}'));
					}

				void operator()(const typename MapType::value_type& node_current,const VisitorMap& visitor)
					{
					putc(visitor.atBegin()?'{':',',r_sink);
					putc('"',r_sink);
					write(node_current.first.c_str(),r_sink);
					auto type_current=node_current.second->type();
					fprintf(r_sink,"\",%s:",type(type_current));
					if(type_current==Type::COMPOUND)
						{
						auto node=VisitorMap::create(node_current.second->template value<MapType>(),'}');
						putc('\n',r_sink);
						if(node->atEnd())
							{putc('{',r_sink);}
						m_stack.push(std::move(node));

						}
					else
					if(type_current==Type::COMPOUND_ARRAY)
						{
						auto node=VisitorArray::create(node_current.second->template value<CompoundArray>(),'}');
						putc('\n',r_sink);
						if(node->atEnd())
							{putc('[',r_sink);}
						m_stack.push(std::move(node));
						}
					else
						{}
					}

			private:
				Sink& r_sink;
				std::stack< std::unique_ptr< VisitorBase<Acceptor> > > m_stack;
			};
		}

	template<class StorageModel,class Sink>
	void temple_store(const ItemBase<StorageModel>& root,Sink& sink)
		{Acceptor<StorageModel,Sink>(root,sink).run();}
	}

#endif
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of detector histogramming module
 * @copyright MIT License
 */

#include "DetectorHistogrammerModule.hpp"

#include <algorithm>
#include <memory>
#include <string>
#include <utility>

#include "core/geometry/HybridPixelDetectorModel.hpp"
#include "core/messenger/Messenger.hpp"
#include "core/utils/log.h"

#include "tools/ROOT.h"

using namespace allpix;

DetectorHistogrammerModule::DetectorHistogrammerModule(Configuration config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), config_(std::move(config)), detector_(std::move(detector)), pixels_message_(nullptr) {
    // Bind pixel hits message
    messenger->bindSingle(this, &DetectorHistogrammerModule::pixels_message_, MsgFlags::REQUIRED);
}

void DetectorHistogrammerModule::init() {
    // Fetch detector model
    auto model = detector_->getModel();

    // Create histogram of hitmap
    LOG(TRACE) << "Creating histograms";
    std::string hit_map_name = "hit_map";
    std::string hit_map_title = "Hitmap for " + detector_->getName() + ";x (pixels);y (pixels)";
    hit_map = new TH2I(hit_map_name.c_str(),
                       hit_map_title.c_str(),
                       model->getNPixels().x(),
                       -0.5,
                       model->getNPixels().x() - 0.5,
                       model->getNPixels().y(),
                       -0.5,
                       model->getNPixels().y() - 0.5);

    // Create histogram of cluster map
    std::string cluster_map_name = "cluster_map";
    std::string cluster_map_title = "Cluster map for " + detector_->getName() + ";x (pixels);y (pixels)";
    cluster_map = new TH2I(cluster_map_name.c_str(),
                           cluster_map_title.c_str(),
                           model->getNPixels().x(),
                           -0.5,
                           model->getNPixels().x() - 0.5,
                           model->getNPixels().y(),
                           -0.5,
                           model->getNPixels().y() - 0.5);

    // Create cluster size plots
    std::string cluster_size_name = "cluster_size";
    std::string cluster_size_title = "Cluster size for " + detector_->getName() + ";size;number";
    cluster_size = new TH1I(cluster_size_name.c_str(),
                            cluster_size_title.c_str(),
                            model->getNPixels().x() * model->getNPixels().y(),
                            0.5,
                            model->getNPixels().x() * model->getNPixels().y() + 0.5);

    std::string cluster_size_x_name = "cluster_size_x";
    std::string cluster_size_x_title = "Cluster size X for " + detector_->getName() + ";size;number";
    cluster_size_x = new TH1I(cluster_size_x_name.c_str(),
                              cluster_size_x_title.c_str(),
                              model->getNPixels().x(),
                              0.5,
                              model->getNPixels().x() + 0.5);

    std::string cluster_size_y_name = "cluster_size_y";
    std::string cluster_size_y_title = "Cluster size Y for " + detector_->getName() + ";size;number";
    cluster_size_y = new TH1I(cluster_size_y_name.c_str(),
                              cluster_size_y_title.c_str(),
                              model->getNPixels().y(),
                              0.5,
                              model->getNPixels().y() + 0.5);

    // Create event size plot
    std::string event_size_name = "event_size";
    std::string event_size_title = "Event size for " + detector_->getName() + ";size;number";
    event_size = new TH1I(event_size_name.c_str(),
                          event_size_title.c_str(),
                          model->getNPixels().x() * model->getNPixels().y(),
                          0.5,
                          model->getNPixels().x() * model->getNPixels().y() + 0.5);

    // Create number of clusters plot
    std::string n_cluster_name = "n_cluster";
    std::string n_cluster_title = "Number of clusters for " + detector_->getName() + ";size;number";
    n_cluster = new TH1I(n_cluster_name.c_str(),
                         n_cluster_title.c_str(),
                         model->getNPixels().x() * model->getNPixels().y(),
                         0.5,
                         model->getNPixels().x() * model->getNPixels().y() + 0.5);

    // Create cluster charge plot
    std::string cluster_charge_name = "cluster_charge";
    std::string cluster_charge_title = "Cluster charge for " + detector_->getName() + ";size;number";
    cluster_charge = new TH1D(cluster_charge_name.c_str(), cluster_charge_title.c_str(), 200, 0., 100.);
}

void DetectorHistogrammerModule::run(unsigned int) {
    LOG(DEBUG) << "Adding hits in " << pixels_message_->getData().size() << " pixels";

    // Fill 2D hitmap histogram
    for(auto& pixel_charge : pixels_message_->getData()) {
        auto pixel_idx = pixel_charge.getPixel().getIndex();

        // Add pixel
        hit_map->Fill(pixel_idx.x(), pixel_idx.y());

        // Update statistics
        total_vector_ += pixel_idx;
        total_hits_ += 1;
    }

    // Perform a clustering
    doClustering();

    // Evaluate the clusters
    for(auto clus : clusters_) {
        LOG(DEBUG) << "Cluster, size " << clus->getClusterSize() << " :";
        for(auto& pixel : clus->getPixelHits()) {
            LOG(DEBUG) << pixel->getPixel().getIndex();
        }
        // Fill cluster histograms
        cluster_size->Fill(static_cast<double>(clus->getClusterSize()));
        auto clusSizesXY = clus->getClusterSizeXY();
        cluster_size_x->Fill(clusSizesXY.first);
        cluster_size_y->Fill(clusSizesXY.second);

        auto clusPos = clus->getClusterPosition();
        cluster_map->Fill(clusPos.x(), clusPos.y());
        cluster_charge->Fill(clus->getClusterCharge() * 1.e-3);
    }

    // Fill further histograms
    event_size->Fill(static_cast<double>(pixels_message_->getData().size()));
    n_cluster->Fill(static_cast<double>(clusters_.size()));

    clusters_.clear();
}

void DetectorHistogrammerModule::finalize() {
    // Print statistics
    if(total_hits_ != 0) {
        LOG(INFO) << "Plotted " << total_hits_ << " hits in total, mean position is "
                  << total_vector_ / static_cast<double>(total_hits_);
    } else {
        LOG(WARNING) << "No hits plotted";
    }

    // FIXME Set more useful spacing maximum for cluster size histogram
    auto xmax = std::ceil(cluster_size->GetBinCenter(cluster_size->FindLastBinAbove()) + 1);
    cluster_size->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_size->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    xmax = std::ceil(cluster_size_x->GetBinCenter(cluster_size_x->FindLastBinAbove()) + 1);
    cluster_size_x->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size_x axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_size_x->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    xmax = std::ceil(cluster_size_y->GetBinCenter(cluster_size_y->FindLastBinAbove()) + 1);
    cluster_size_y->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size_y axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_size_y->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // FIXME Set more useful spacing maximum for event size histogram
    xmax = std::ceil(event_size->GetBinCenter(event_size->FindLastBinAbove()) + 1);
    event_size->GetXaxis()->SetRangeUser(0, xmax);
    // Set event size axis spacing
    if(static_cast<int>(xmax) < 10) {
        event_size->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // FIXME Set more useful spacing maximum for n_cluster histogram
    xmax = std::ceil(n_cluster->GetBinCenter(n_cluster->FindLastBinAbove()) + 1);
    n_cluster->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size axis spacing
    if(static_cast<int>(xmax) < 10) {
        n_cluster->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // FIXME Set more useful spacing maximum for cluster_charge histogram
    xmax = std::ceil(cluster_charge->GetBinCenter(cluster_charge->FindLastBinAbove()) + 1);
    cluster_charge->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_charge->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // Set default drawing option histogram for hitmap
    hit_map->SetOption("colz");
    // Set hit_map axis spacing
    if(static_cast<int>(hit_map->GetXaxis()->GetXmax()) < 10) {
        hit_map->GetXaxis()->SetNdivisions(static_cast<int>(hit_map->GetXaxis()->GetXmax()) + 1, 0, 0, true);
    }
    if(static_cast<int>(hit_map->GetYaxis()->GetXmax()) < 10) {
        hit_map->GetYaxis()->SetNdivisions(static_cast<int>(hit_map->GetYaxis()->GetXmax()) + 1, 0, 0, true);
    }

    cluster_map->SetOption("colz");
    // Set cluster_map axis spacing
    if(static_cast<int>(cluster_map->GetXaxis()->GetXmax()) < 10) {
        cluster_map->GetXaxis()->SetNdivisions(static_cast<int>(cluster_map->GetXaxis()->GetXmax()) + 1, 0, 0, true);
    }
    if(static_cast<int>(cluster_map->GetYaxis()->GetXmax()) < 10) {
        cluster_map->GetYaxis()->SetNdivisions(static_cast<int>(cluster_map->GetYaxis()->GetXmax()) + 1, 0, 0, true);
    }

    // Write histograms
    LOG(TRACE) << "Writing histograms to file";
    hit_map->Write();
    cluster_map->Write();
    cluster_size->Write();
    cluster_size_x->Write();
    cluster_size_y->Write();
    event_size->Write();
    n_cluster->Write();
    cluster_charge->Write();
}

void DetectorHistogrammerModule::doClustering() {
    for(auto& pixel_hit : pixels_message_->getData()) {
        Cluster* clus;
        if(not checkAdjacentPixels(&pixel_hit)) {
            LOG(DEBUG) << "Creating new cluster: " << pixel_hit.getPixel().getIndex();
            clus = new Cluster(&pixel_hit);
            clusters_.push_back(clus);
        }
    }
}

bool DetectorHistogrammerModule::isInCluster(const PixelHit* pixel_hit) {
    for(auto clus : clusters_) {
        for(auto& hit : clus->getPixelHits()) {
            if(pixel_hit == hit) {
                return true;
            }
        }
    }
    return false;
}

bool DetectorHistogrammerModule::checkAdjacentPixels(const PixelHit* pixel_hit) {
    auto hit_idx = pixel_hit->getPixel().getIndex();
    for(auto clus : clusters_) {
        for(auto& pixel_other : clus->getPixelHits()) {
            auto other_idx = pixel_other->getPixel().getIndex();
            auto distx = std::max(hit_idx.x(), other_idx.x()) - std::min(hit_idx.x(), other_idx.x());
            auto disty = std::max(hit_idx.y(), other_idx.y()) - std::min(hit_idx.y(), other_idx.y());
            if(distx <= 1 and disty <= 1) {
                LOG(DEBUG) << "Adding pixel to cluster: " << hit_idx;
                bool ret = clus->addPixelHit(pixel_hit);
                if(ret == false) {
                    LOG(DEBUG) << "Hit has already been added to this cluster: " << hit_idx;
                }
                return true;
            }
        }
    }
    return false;
}
<commit_msg>Change axes labels<commit_after>/**
 * @file
 * @brief Implementation of detector histogramming module
 * @copyright MIT License
 */

#include "DetectorHistogrammerModule.hpp"

#include <algorithm>
#include <memory>
#include <string>
#include <utility>

#include "core/geometry/HybridPixelDetectorModel.hpp"
#include "core/messenger/Messenger.hpp"
#include "core/utils/log.h"

#include "tools/ROOT.h"

using namespace allpix;

DetectorHistogrammerModule::DetectorHistogrammerModule(Configuration config,
                                                       Messenger* messenger,
                                                       std::shared_ptr<Detector> detector)
    : Module(config, detector), config_(std::move(config)), detector_(std::move(detector)), pixels_message_(nullptr) {
    // Bind pixel hits message
    messenger->bindSingle(this, &DetectorHistogrammerModule::pixels_message_, MsgFlags::REQUIRED);
}

void DetectorHistogrammerModule::init() {
    // Fetch detector model
    auto model = detector_->getModel();

    // Create histogram of hitmap
    LOG(TRACE) << "Creating histograms";
    std::string hit_map_name = "hit_map";
    std::string hit_map_title = "Hitmap for " + detector_->getName() + ";x (pixels);y (pixels)";
    hit_map = new TH2I(hit_map_name.c_str(),
                       hit_map_title.c_str(),
                       model->getNPixels().x(),
                       -0.5,
                       model->getNPixels().x() - 0.5,
                       model->getNPixels().y(),
                       -0.5,
                       model->getNPixels().y() - 0.5);

    // Create histogram of cluster map
    std::string cluster_map_name = "cluster_map";
    std::string cluster_map_title = "Cluster map for " + detector_->getName() + ";x (pixels);y (pixels)";
    cluster_map = new TH2I(cluster_map_name.c_str(),
                           cluster_map_title.c_str(),
                           model->getNPixels().x(),
                           -0.5,
                           model->getNPixels().x() - 0.5,
                           model->getNPixels().y(),
                           -0.5,
                           model->getNPixels().y() - 0.5);

    // Create cluster size plots
    std::string cluster_size_name = "cluster_size";
    std::string cluster_size_title = "Cluster size for " + detector_->getName() + ";cluster size [px];clusters";
    cluster_size = new TH1I(cluster_size_name.c_str(),
                            cluster_size_title.c_str(),
                            model->getNPixels().x() * model->getNPixels().y(),
                            0.5,
                            model->getNPixels().x() * model->getNPixels().y() + 0.5);

    std::string cluster_size_x_name = "cluster_size_x";
    std::string cluster_size_x_title = "Cluster size X for " + detector_->getName() + ";cluster size x [px];clusters";
    cluster_size_x = new TH1I(cluster_size_x_name.c_str(),
                              cluster_size_x_title.c_str(),
                              model->getNPixels().x(),
                              0.5,
                              model->getNPixels().x() + 0.5);

    std::string cluster_size_y_name = "cluster_size_y";
    std::string cluster_size_y_title = "Cluster size Y for " + detector_->getName() + ";cluster size y [px];clusters";
    cluster_size_y = new TH1I(cluster_size_y_name.c_str(),
                              cluster_size_y_title.c_str(),
                              model->getNPixels().y(),
                              0.5,
                              model->getNPixels().y() + 0.5);

    // Create event size plot
    std::string event_size_name = "event_size";
    std::string event_size_title = "Event size for " + detector_->getName() + ";event size [px];events";
    event_size = new TH1I(event_size_name.c_str(),
                          event_size_title.c_str(),
                          model->getNPixels().x() * model->getNPixels().y(),
                          0.5,
                          model->getNPixels().x() * model->getNPixels().y() + 0.5);

    // Create number of clusters plot
    std::string n_cluster_name = "n_cluster";
    std::string n_cluster_title = "Number of clusters for " + detector_->getName() + ";size;clusters";
    n_cluster = new TH1I(n_cluster_name.c_str(),
                         n_cluster_title.c_str(),
                         model->getNPixels().x() * model->getNPixels().y(),
                         0.5,
                         model->getNPixels().x() * model->getNPixels().y() + 0.5);

    // Create cluster charge plot
    std::string cluster_charge_name = "cluster_charge";
    std::string cluster_charge_title = "Cluster charge for " + detector_->getName() + ";cluster charge [ke];clusters";
    cluster_charge = new TH1D(cluster_charge_name.c_str(), cluster_charge_title.c_str(), 200, 0., 100.);
}

void DetectorHistogrammerModule::run(unsigned int) {
    LOG(DEBUG) << "Adding hits in " << pixels_message_->getData().size() << " pixels";

    // Fill 2D hitmap histogram
    for(auto& pixel_charge : pixels_message_->getData()) {
        auto pixel_idx = pixel_charge.getPixel().getIndex();

        // Add pixel
        hit_map->Fill(pixel_idx.x(), pixel_idx.y());

        // Update statistics
        total_vector_ += pixel_idx;
        total_hits_ += 1;
    }

    // Perform a clustering
    doClustering();

    // Evaluate the clusters
    for(auto clus : clusters_) {
        LOG(DEBUG) << "Cluster, size " << clus->getClusterSize() << " :";
        for(auto& pixel : clus->getPixelHits()) {
            LOG(DEBUG) << pixel->getPixel().getIndex();
        }
        // Fill cluster histograms
        cluster_size->Fill(static_cast<double>(clus->getClusterSize()));
        auto clusSizesXY = clus->getClusterSizeXY();
        cluster_size_x->Fill(clusSizesXY.first);
        cluster_size_y->Fill(clusSizesXY.second);

        auto clusPos = clus->getClusterPosition();
        cluster_map->Fill(clusPos.x(), clusPos.y());
        cluster_charge->Fill(clus->getClusterCharge() * 1.e-3);
    }

    // Fill further histograms
    event_size->Fill(static_cast<double>(pixels_message_->getData().size()));
    n_cluster->Fill(static_cast<double>(clusters_.size()));

    clusters_.clear();
}

void DetectorHistogrammerModule::finalize() {
    // Print statistics
    if(total_hits_ != 0) {
        LOG(INFO) << "Plotted " << total_hits_ << " hits in total, mean position is "
                  << total_vector_ / static_cast<double>(total_hits_);
    } else {
        LOG(WARNING) << "No hits plotted";
    }

    // FIXME Set more useful spacing maximum for cluster size histogram
    auto xmax = std::ceil(cluster_size->GetBinCenter(cluster_size->FindLastBinAbove()) + 1);
    cluster_size->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_size->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    xmax = std::ceil(cluster_size_x->GetBinCenter(cluster_size_x->FindLastBinAbove()) + 1);
    cluster_size_x->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size_x axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_size_x->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    xmax = std::ceil(cluster_size_y->GetBinCenter(cluster_size_y->FindLastBinAbove()) + 1);
    cluster_size_y->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size_y axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_size_y->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // FIXME Set more useful spacing maximum for event size histogram
    xmax = std::ceil(event_size->GetBinCenter(event_size->FindLastBinAbove()) + 1);
    event_size->GetXaxis()->SetRangeUser(0, xmax);
    // Set event size axis spacing
    if(static_cast<int>(xmax) < 10) {
        event_size->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // FIXME Set more useful spacing maximum for n_cluster histogram
    xmax = std::ceil(n_cluster->GetBinCenter(n_cluster->FindLastBinAbove()) + 1);
    n_cluster->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size axis spacing
    if(static_cast<int>(xmax) < 10) {
        n_cluster->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // FIXME Set more useful spacing maximum for cluster_charge histogram
    xmax = std::ceil(cluster_charge->GetBinCenter(cluster_charge->FindLastBinAbove()) + 1);
    cluster_charge->GetXaxis()->SetRangeUser(0, xmax);
    // Set cluster size axis spacing
    if(static_cast<int>(xmax) < 10) {
        cluster_charge->GetXaxis()->SetNdivisions(static_cast<int>(xmax) + 1, 0, 0, true);
    }

    // Set default drawing option histogram for hitmap
    hit_map->SetOption("colz");
    // Set hit_map axis spacing
    if(static_cast<int>(hit_map->GetXaxis()->GetXmax()) < 10) {
        hit_map->GetXaxis()->SetNdivisions(static_cast<int>(hit_map->GetXaxis()->GetXmax()) + 1, 0, 0, true);
    }
    if(static_cast<int>(hit_map->GetYaxis()->GetXmax()) < 10) {
        hit_map->GetYaxis()->SetNdivisions(static_cast<int>(hit_map->GetYaxis()->GetXmax()) + 1, 0, 0, true);
    }

    cluster_map->SetOption("colz");
    // Set cluster_map axis spacing
    if(static_cast<int>(cluster_map->GetXaxis()->GetXmax()) < 10) {
        cluster_map->GetXaxis()->SetNdivisions(static_cast<int>(cluster_map->GetXaxis()->GetXmax()) + 1, 0, 0, true);
    }
    if(static_cast<int>(cluster_map->GetYaxis()->GetXmax()) < 10) {
        cluster_map->GetYaxis()->SetNdivisions(static_cast<int>(cluster_map->GetYaxis()->GetXmax()) + 1, 0, 0, true);
    }

    // Write histograms
    LOG(TRACE) << "Writing histograms to file";
    hit_map->Write();
    cluster_map->Write();
    cluster_size->Write();
    cluster_size_x->Write();
    cluster_size_y->Write();
    event_size->Write();
    n_cluster->Write();
    cluster_charge->Write();
}

void DetectorHistogrammerModule::doClustering() {
    for(auto& pixel_hit : pixels_message_->getData()) {
        Cluster* clus;
        if(not checkAdjacentPixels(&pixel_hit)) {
            LOG(DEBUG) << "Creating new cluster: " << pixel_hit.getPixel().getIndex();
            clus = new Cluster(&pixel_hit);
            clusters_.push_back(clus);
        }
    }
}

bool DetectorHistogrammerModule::isInCluster(const PixelHit* pixel_hit) {
    for(auto clus : clusters_) {
        for(auto& hit : clus->getPixelHits()) {
            if(pixel_hit == hit) {
                return true;
            }
        }
    }
    return false;
}

bool DetectorHistogrammerModule::checkAdjacentPixels(const PixelHit* pixel_hit) {
    auto hit_idx = pixel_hit->getPixel().getIndex();
    for(auto clus : clusters_) {
        for(auto& pixel_other : clus->getPixelHits()) {
            auto other_idx = pixel_other->getPixel().getIndex();
            auto distx = std::max(hit_idx.x(), other_idx.x()) - std::min(hit_idx.x(), other_idx.x());
            auto disty = std::max(hit_idx.y(), other_idx.y()) - std::min(hit_idx.y(), other_idx.y());
            if(distx <= 1 and disty <= 1) {
                LOG(DEBUG) << "Adding pixel to cluster: " << hit_idx;
                bool ret = clus->addPixelHit(pixel_hit);
                if(ret == false) {
                    LOG(DEBUG) << "Hit has already been added to this cluster: " << hit_idx;
                }
                return true;
            }
        }
    }
    return false;
}
<|endoftext|>