<commit_before>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/nw_package.h"

#include <vector>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/common/zip.h"
#include "content/nw/src/common/shell_switches.h"
#include "googleurl/src/gurl.h"
#include "grit/nw_resources.h"
#include "net/base/escape.h"
#include "third_party/node/deps/uv/include/uv.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "webkit/glue/image_decoder.h"

namespace nw {

namespace {

#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif

bool MakePathAbsolute(FilePath* file_path) {
  DCHECK(file_path);

  FilePath current_directory;
  if (!file_util::GetCurrentDirectory(&current_directory))
    return false;

  if (file_path->IsAbsolute())
    return true;

  if (current_directory.empty())
    return file_util::AbsolutePath(file_path);

  if (!current_directory.IsAbsolute())
    return false;

  *file_path = current_directory.Append(*file_path);
  return true;
}

FilePath GetSelfPath() {
  CommandLine* command_line = CommandLine::ForCurrentProcess();

  FilePath path;

  size_t size = 2*PATH_MAX;
  char* execPath = new char[size];
  if (uv_exepath(execPath, &size) == 0) {
    path = FilePath::FromUTF8Unsafe(std::string(execPath, size));
  } else {
    path = FilePath(command_line->GetProgram());
  }

#if defined(OS_MACOSX)
  // Find if we have node-webkit.app/Resources/app.nw.
  path = path.DirName().DirName().Append("Resources").Append("app.nw");
#endif

  return path;
}

void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) {
  std::string old;
  if (!manifest->GetString(switches::kmMain, &old))
    return;

  // Don't append path if there is already a prefix
  if (MatchPattern(old, "*://*"))
    return;

  FilePath main_path = root.Append(FilePath::FromUTF8Unsafe(old));
  manifest->SetString(switches::kmMain,
                      std::string("file://") + main_path.AsUTF8Unsafe());
}

}  // namespace

Package::Package()
    : path_(GetSelfPath()),
      self_extract_(true) {
  // First try to extract self.
  if (InitFromPath())
    return;

  // Then see if we have arguments and extract it.
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  const CommandLine::StringVector& args = command_line->GetArgs();
  if (args.size() > 0) {
    self_extract_ = false;
    path_ = FilePath(args[0]);
    if (InitFromPath())
      return;
  }

  // Finally we init with default settings.
  self_extract_ = false;
  InitWithDefault();
}

Package::Package(FilePath path)
    : path_(path),
      self_extract_(false) {
  if (!InitFromPath())
    InitWithDefault();
}

Package::~Package() {
}

FilePath Package::ConvertToAbsoutePath(const FilePath& path) {
  if (path.IsAbsolute())
    return path;

  return this->path().Append(path);
}

bool Package::GetImage(const FilePath& icon_path, gfx::Image* image) {
  FilePath path = ConvertToAbsoutePath(icon_path);

  // Read the file from disk.
  std::string file_contents;
  if (path.empty() || !file_util::ReadFileToString(path, &file_contents))
    return false;

  // Decode the bitmap using WebKit's image decoder.
  const unsigned char* data =
      reinterpret_cast<const unsigned char*>(file_contents.data());
  webkit_glue::ImageDecoder decoder;
  scoped_ptr<SkBitmap> decoded(new SkBitmap());
  // Note: This class only decodes bitmaps from extension resources. Chrome
  // doesn't (for security reasons) directly load extension resources provided
  // by the extension author, but instead decodes them in a separate
  // locked-down utility process. Only if the decoding succeeds is the image
  // saved from memory to disk and subsequently used in the Chrome UI.
  // Chrome is therefore decoding bitmaps here that were generated by Chrome.
  *decoded = decoder.Decode(data, file_contents.length());
  if (decoded->empty())
    return false;  // Unable to decode.

  *image = gfx::Image(*decoded.release());
  return true;
}

GURL Package::GetStartupURL() {
  std::string url;
  // Specify URL in --url
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kUrl)) {
    url = command_line->GetSwitchValueASCII(switches::kUrl);
    GURL gurl(url);
    if (!gurl.has_scheme())
      return GURL(std::string("http://") + url);

    return gurl;
  }

  // Report if encountered errors.
  if (!error_page_url_.empty())
    return GURL(error_page_url_);

  // Read from manifest.
  if (root()->GetString(switches::kmMain, &url))
    return GURL(url);
  else
    return GURL("nw:blank");
}

std::string Package::GetName() {
  std::string name("node-webkit");
  root()->GetString(switches::kmName, &name);
  return name;
}

bool Package::GetUseNode() {
  bool use_node = true;
  root()->GetBoolean(switches::kmNodejs, &use_node);
  return use_node;
}

base::DictionaryValue* Package::window() {
  base::DictionaryValue* window;
  root()->GetDictionaryWithoutPathExpansion(switches::kmWindow, &window);
  return window;
}

bool Package::InitFromPath() {
  base::ThreadRestrictions::SetIOAllowed(true);

  if (!ExtractPath())
    return false;

  // path_/package.json
  FilePath manifest_path = path_.AppendASCII("package.json");
  if (!file_util::PathExists(manifest_path)) {
    if (!self_extract())
      ReportError("Invalid package",
                  "There is no 'package.json' in the package, please make "
                  "sure the 'package.json' is in the root of the package.");
    return false;
  }

  // Parse file.
  std::string error;
  JSONFileValueSerializer serializer(manifest_path);
  scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
  if (!root.get()) {
    ReportError("Unable to parse package.json",
                error.empty() ?
                    "Failed to read the manifest file: " +
                        manifest_path.AsUTF8Unsafe() :
                    error);
    return false;
  } else if (!root->IsType(Value::TYPE_DICTIONARY)) {
    ReportError("Invalid package.json",
                "package.json's content should be a object type.");
    return false;
  }

  // Save result in global
  root_.reset(static_cast<DictionaryValue*>(root.release()));

  // Check fields
  const char* required_fields[] = {
    switches::kmMain,
    switches::kmName
  };
  for (unsigned i = 0; i < arraysize(required_fields); i++)
    if (!root_->HasKey(required_fields[i])) {
      ReportError("Invalid package.json",
                  std::string("Field '") + required_fields[i] + "'"
                      " is required.");
      return false;
    }

  // Force window field no empty.
  if (!root_->HasKey(switches::kmWindow)) {
    base::DictionaryValue* window = new base::DictionaryValue();
    window->SetString(switches::kmPosition, "center");
    root_->Set(switches::kmWindow, window);
  }

  RelativePathToURI(path_, this->root());
  return true;
}

void Package::InitWithDefault() {
  root_.reset(new base::DictionaryValue());
  root()->SetString(switches::kmName, "node-webkit");
  root()->SetString(switches::kmMain, "nw:blank");
  base::DictionaryValue* window = new base::DictionaryValue();
  root()->Set(switches::kmWindow, window);

  // Hide toolbar if specifed in the command line.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoToolbar))
    window->SetBoolean(switches::kmToolbar, false);

  // Window should show in center by default.
  window->SetString(switches::kmPosition, "center");
}

bool Package::ExtractPath() {
  // Convert to absoulute path.
  if (!MakePathAbsolute(&path_)) {
    ReportError("Cannot extract package",
                "Path is invalid: " + path_.AsUTF8Unsafe());
    return false;
  }

  // Read symbolic link.
#if defined(OS_POSIX)
  FilePath target;
  if (file_util::ReadSymbolicLink(path_, &target))
    path_ = target;
#endif

  // If it's a file then try to extract from it.
  if (!file_util::DirectoryExists(path_)) {
    FilePath extracted_path;
    if (ExtractPackage(path_, &extracted_path)) {
      path_ = extracted_path;
    } else if (!self_extract()) {
      ReportError("Cannot extract package",
                  "Failed to unzip the package file: " + path_.AsUTF8Unsafe());
      return false;
    }
  }

  return true;
}

bool Package::ExtractPackage(const FilePath& zip_file, FilePath* where) {
  // Auto clean our temporary directory
  static scoped_ptr<ScopedTempDir> scoped_temp_dir;

#if defined(OS_WIN)
  if (!file_util::CreateNewTempDirectory(L"nw", where)) {
#else
  if (!file_util::CreateNewTempDirectory("nw", where)) {
#endif
    ReportError("Cannot extract package",
                "Unable to create temporary directory.");
    return false;
  }

  scoped_temp_dir.reset(new ScopedTempDir());
  if (!scoped_temp_dir->Set(*where)) {
    ReportError("Cannot extract package",
                "Unable to set temporary directory.");
    return false;
  }

  return zip::Unzip(zip_file, *where);
}

void Package::ReportError(const std::string& title,
                          const std::string& content) {
  if (!error_page_url_.empty())
    return;

  const base::StringPiece template_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_NW_PACKAGE_ERROR));

  if (template_html.empty()) {
    // Print hand written error info if nw.pak doesn't exist.
    NOTREACHED() << "Unable to load error template.";
    error_page_url_ = "data:text/html;base64,VW5hYmxlIHRvIGZpbmQgbncucGFrLgo=";
    return;
  }

  std::vector<std::string> subst;
  subst.push_back(title);
  subst.push_back(content);
  error_page_url_ = "data:text/html;charset=utf-8," +
      net::EscapeQueryParamValue(
          ReplaceStringPlaceholders(template_html, subst, NULL), false);
}

}  // namespace nw
<commit_msg>find app in the same directory as exe when no arguments are given<commit_after>// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/nw_package.h"

#include <vector>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/common/zip.h"
#include "content/nw/src/common/shell_switches.h"
#include "googleurl/src/gurl.h"
#include "grit/nw_resources.h"
#include "net/base/escape.h"
#include "third_party/node/deps/uv/include/uv.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "webkit/glue/image_decoder.h"

namespace nw {

namespace {

#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif

bool MakePathAbsolute(FilePath* file_path) {
  DCHECK(file_path);

  FilePath current_directory;
  if (!file_util::GetCurrentDirectory(&current_directory))
    return false;

  if (file_path->IsAbsolute())
    return true;

  if (current_directory.empty())
    return file_util::AbsolutePath(file_path);

  if (!current_directory.IsAbsolute())
    return false;

  *file_path = current_directory.Append(*file_path);
  return true;
}

FilePath GetSelfPath() {
  CommandLine* command_line = CommandLine::ForCurrentProcess();

  FilePath path;

  size_t size = 2*PATH_MAX;
  char* execPath = new char[size];
  if (uv_exepath(execPath, &size) == 0) {
    path = FilePath::FromUTF8Unsafe(std::string(execPath, size));
  } else {
    path = FilePath(command_line->GetProgram());
  }

#if defined(OS_MACOSX)
  // Find if we have node-webkit.app/Resources/app.nw.
  path = path.DirName().DirName().Append("Resources").Append("app.nw");
#endif

  return path;
}

void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) {
  std::string old;
  if (!manifest->GetString(switches::kmMain, &old))
    return;

  // Don't append path if there is already a prefix
  if (MatchPattern(old, "*://*"))
    return;

  FilePath main_path = root.Append(FilePath::FromUTF8Unsafe(old));
  manifest->SetString(switches::kmMain,
                      std::string("file://") + main_path.AsUTF8Unsafe());
}

}  // namespace

Package::Package()
    : path_(GetSelfPath()),
      self_extract_(true) {
  // First try to extract self.
  if (InitFromPath())
    return;

  self_extract_ = false;
  // Then see if we have arguments and extract it.
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  const CommandLine::StringVector& args = command_line->GetArgs();
  if (args.size() > 0) {
    path_ = FilePath(args[0]);
  } else {
    // Try to load from the folder where the exe resides
    path_ = GetSelfPath().DirName();
  }
  if (InitFromPath())
    return;

  // Finally we init with default settings.
  InitWithDefault();
}

Package::Package(FilePath path)
    : path_(path),
      self_extract_(false) {
  if (!InitFromPath())
    InitWithDefault();
}

Package::~Package() {
}

FilePath Package::ConvertToAbsoutePath(const FilePath& path) {
  if (path.IsAbsolute())
    return path;

  return this->path().Append(path);
}

bool Package::GetImage(const FilePath& icon_path, gfx::Image* image) {
  FilePath path = ConvertToAbsoutePath(icon_path);

  // Read the file from disk.
  std::string file_contents;
  if (path.empty() || !file_util::ReadFileToString(path, &file_contents))
    return false;

  // Decode the bitmap using WebKit's image decoder.
  const unsigned char* data =
      reinterpret_cast<const unsigned char*>(file_contents.data());
  webkit_glue::ImageDecoder decoder;
  scoped_ptr<SkBitmap> decoded(new SkBitmap());
  // Note: This class only decodes bitmaps from extension resources. Chrome
  // doesn't (for security reasons) directly load extension resources provided
  // by the extension author, but instead decodes them in a separate
  // locked-down utility process. Only if the decoding succeeds is the image
  // saved from memory to disk and subsequently used in the Chrome UI.
  // Chrome is therefore decoding bitmaps here that were generated by Chrome.
  *decoded = decoder.Decode(data, file_contents.length());
  if (decoded->empty())
    return false;  // Unable to decode.

  *image = gfx::Image(*decoded.release());
  return true;
}

GURL Package::GetStartupURL() {
  std::string url;
  // Specify URL in --url
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kUrl)) {
    url = command_line->GetSwitchValueASCII(switches::kUrl);
    GURL gurl(url);
    if (!gurl.has_scheme())
      return GURL(std::string("http://") + url);

    return gurl;
  }

  // Report if encountered errors.
  if (!error_page_url_.empty())
    return GURL(error_page_url_);

  // Read from manifest.
  if (root()->GetString(switches::kmMain, &url))
    return GURL(url);
  else
    return GURL("nw:blank");
}

std::string Package::GetName() {
  std::string name("node-webkit");
  root()->GetString(switches::kmName, &name);
  return name;
}

bool Package::GetUseNode() {
  bool use_node = true;
  root()->GetBoolean(switches::kmNodejs, &use_node);
  return use_node;
}

base::DictionaryValue* Package::window() {
  base::DictionaryValue* window;
  root()->GetDictionaryWithoutPathExpansion(switches::kmWindow, &window);
  return window;
}

bool Package::InitFromPath() {
  base::ThreadRestrictions::SetIOAllowed(true);

  if (!ExtractPath())
    return false;

  // path_/package.json
  FilePath manifest_path = path_.AppendASCII("package.json");
  if (!file_util::PathExists(manifest_path)) {
    if (!self_extract())
      ReportError("Invalid package",
                  "There is no 'package.json' in the package, please make "
                  "sure the 'package.json' is in the root of the package.");
    return false;
  }

  // Parse file.
  std::string error;
  JSONFileValueSerializer serializer(manifest_path);
  scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
  if (!root.get()) {
    ReportError("Unable to parse package.json",
                error.empty() ?
                    "Failed to read the manifest file: " +
                        manifest_path.AsUTF8Unsafe() :
                    error);
    return false;
  } else if (!root->IsType(Value::TYPE_DICTIONARY)) {
    ReportError("Invalid package.json",
                "package.json's content should be a object type.");
    return false;
  }

  // Save result in global
  root_.reset(static_cast<DictionaryValue*>(root.release()));

  // Check fields
  const char* required_fields[] = {
    switches::kmMain,
    switches::kmName
  };
  for (unsigned i = 0; i < arraysize(required_fields); i++)
    if (!root_->HasKey(required_fields[i])) {
      ReportError("Invalid package.json",
                  std::string("Field '") + required_fields[i] + "'"
                      " is required.");
      return false;
    }

  // Force window field no empty.
  if (!root_->HasKey(switches::kmWindow)) {
    base::DictionaryValue* window = new base::DictionaryValue();
    window->SetString(switches::kmPosition, "center");
    root_->Set(switches::kmWindow, window);
  }

  RelativePathToURI(path_, this->root());
  return true;
}

void Package::InitWithDefault() {
  root_.reset(new base::DictionaryValue());
  root()->SetString(switches::kmName, "node-webkit");
  root()->SetString(switches::kmMain, "nw:blank");
  base::DictionaryValue* window = new base::DictionaryValue();
  root()->Set(switches::kmWindow, window);

  // Hide toolbar if specifed in the command line.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoToolbar))
    window->SetBoolean(switches::kmToolbar, false);

  // Window should show in center by default.
  window->SetString(switches::kmPosition, "center");
}

bool Package::ExtractPath() {
  // Convert to absoulute path.
  if (!MakePathAbsolute(&path_)) {
    ReportError("Cannot extract package",
                "Path is invalid: " + path_.AsUTF8Unsafe());
    return false;
  }

  // Read symbolic link.
#if defined(OS_POSIX)
  FilePath target;
  if (file_util::ReadSymbolicLink(path_, &target))
    path_ = target;
#endif

  // If it's a file then try to extract from it.
  if (!file_util::DirectoryExists(path_)) {
    FilePath extracted_path;
    if (ExtractPackage(path_, &extracted_path)) {
      path_ = extracted_path;
    } else if (!self_extract()) {
      ReportError("Cannot extract package",
                  "Failed to unzip the package file: " + path_.AsUTF8Unsafe());
      return false;
    }
  }

  return true;
}

bool Package::ExtractPackage(const FilePath& zip_file, FilePath* where) {
  // Auto clean our temporary directory
  static scoped_ptr<ScopedTempDir> scoped_temp_dir;

#if defined(OS_WIN)
  if (!file_util::CreateNewTempDirectory(L"nw", where)) {
#else
  if (!file_util::CreateNewTempDirectory("nw", where)) {
#endif
    ReportError("Cannot extract package",
                "Unable to create temporary directory.");
    return false;
  }

  scoped_temp_dir.reset(new ScopedTempDir());
  if (!scoped_temp_dir->Set(*where)) {
    ReportError("Cannot extract package",
                "Unable to set temporary directory.");
    return false;
  }

  return zip::Unzip(zip_file, *where);
}

void Package::ReportError(const std::string& title,
                          const std::string& content) {
  if (!error_page_url_.empty())
    return;

  const base::StringPiece template_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_NW_PACKAGE_ERROR));

  if (template_html.empty()) {
    // Print hand written error info if nw.pak doesn't exist.
    NOTREACHED() << "Unable to load error template.";
    error_page_url_ = "data:text/html;base64,VW5hYmxlIHRvIGZpbmQgbncucGFrLgo=";
    return;
  }

  std::vector<std::string> subst;
  subst.push_back(title);
  subst.push_back(content);
  error_page_url_ = "data:text/html;charset=utf-8," +
      net::EscapeQueryParamValue(
          ReplaceStringPlaceholders(template_html, subst, NULL), false);
}

}  // namespace nw
<|endoftext|>


<commit_before>
//
//	HSP3 stack support
//	(ėpX^bN}l[W[)
//	(int,double,stringȂǂ̉ϒf[^push,popł܂)
//	onion software/onitama 2004/6
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include "hspvar_core.h"
#include "hsp3debug.h"

/*------------------------------------------------------------*/
/*
		system data
*/
/*------------------------------------------------------------*/

int stm_max;
int stm_cur;
STMDATA *mem_stm;

/*------------------------------------------------------------*/
/*
		interface
*/
/*------------------------------------------------------------*/

void StackInit( void )
{
	stm_max = STM_MAX_DEFAULT;
	mem_stm = (STMDATA *)malloc( sizeof( STMDATA ) * stm_max );
	stm_cur = 0;
}

void StackTerm( void )
{
	StackReset();
	free( mem_stm );
}

static void StackAlloc( STMDATA *stm, int size )
{
	stm->mode = STMMODE_ALLOC;
	stm->ptr = (char *)malloc( size );
}

void StackReset( void )
{
	while(1) {
		if ( stm_cur == 0 ) break;
		StackPop();
	}
}

void StackPush( int type, char *data, int size )
{
	STMDATA *stm;
	double *dptr;
	if ( stm_cur > stm_max ) throw HSPERR_STACK_OVERFLOW;
	stm = &mem_stm[ stm_cur ];
	stm->type = type;
	stm->mode = STMMODE_SELF;
	switch( type ) {
	case HSPVAR_FLAG_LABEL:
	case HSPVAR_FLAG_INT:
		stm->ival = *(int *)data;
		stm->ptr = (char *)&(stm->ival);
		stm_cur++;
		return;
	case HSPVAR_FLAG_DOUBLE:
		dptr = (double *)&stm->ival;
		*dptr = *(double *)data;
		stm->ptr = (char *)dptr;
		stm_cur++;
		return;
	default:
		break;
	}
	StackAlloc( stm, size );
	memcpy( stm->ptr, data, size );
	stm_cur++;
}

void StackPush( int type, char *str )
{
	StackPush( type, str, (int)strlen(str)+1 );
}

void *StackPushSize( int type, int size )
{
	STMDATA *stm;
	if ( stm_cur > stm_max ) throw HSPERR_STACK_OVERFLOW;
	stm = &mem_stm[ stm_cur ];
	stm->type = type;
	StackAlloc( stm, size );
	stm_cur++;
	return (void *)stm->ptr;
}

void StackPushi( int val )
{
	STMDATA *stm;
	if ( stm_cur > stm_max ) throw HSPERR_STACK_OVERFLOW;
	stm = &mem_stm[ stm_cur ];
	stm->type = HSPVAR_FLAG_INT;
	stm->mode = STMMODE_SELF;
	stm->ptr = (char *)&(stm->ival);
	stm->ival = val;
	stm_cur++;
}

void StackPop( void )
{
	if ( stm_cur == 0 ) throw HSPERR_UNKNOWN_CODE;
	stm_cur--;
	if ( mem_stm[ stm_cur ].mode ) {
		free( mem_stm[ stm_cur ].ptr );
	}
}

<commit_msg>stack.cpp のオーバーランチェックの式を修正<commit_after>
//
//	HSP3 stack support
//	(ėpX^bN}l[W[)
//	(int,double,stringȂǂ̉ϒf[^push,popł܂)
//	onion software/onitama 2004/6
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stack.h"
#include "hspvar_core.h"
#include "hsp3debug.h"

/*------------------------------------------------------------*/
/*
		system data
*/
/*------------------------------------------------------------*/

int stm_max;
int stm_cur;
STMDATA *mem_stm;

/*------------------------------------------------------------*/
/*
		interface
*/
/*------------------------------------------------------------*/

void StackInit( void )
{
	stm_max = STM_MAX_DEFAULT;
	mem_stm = (STMDATA *)malloc( sizeof( STMDATA ) * stm_max );
	stm_cur = 0;
}

void StackTerm( void )
{
	StackReset();
	free( mem_stm );
}

static void StackAlloc( STMDATA *stm, int size )
{
	stm->mode = STMMODE_ALLOC;
	stm->ptr = (char *)malloc( size );
}

void StackReset( void )
{
	while(1) {
		if ( stm_cur == 0 ) break;
		StackPop();
	}
}

void StackPush( int type, char *data, int size )
{
	STMDATA *stm;
	double *dptr;
	if ( stm_cur >= stm_max ) throw HSPERR_STACK_OVERFLOW;
	stm = &mem_stm[ stm_cur ];
	stm->type = type;
	stm->mode = STMMODE_SELF;
	switch( type ) {
	case HSPVAR_FLAG_LABEL:
	case HSPVAR_FLAG_INT:
		stm->ival = *(int *)data;
		stm->ptr = (char *)&(stm->ival);
		stm_cur++;
		return;
	case HSPVAR_FLAG_DOUBLE:
		dptr = (double *)&stm->ival;
		*dptr = *(double *)data;
		stm->ptr = (char *)dptr;
		stm_cur++;
		return;
	default:
		break;
	}
	StackAlloc( stm, size );
	memcpy( stm->ptr, data, size );
	stm_cur++;
}

void StackPush( int type, char *str )
{
	StackPush( type, str, (int)strlen(str)+1 );
}

void *StackPushSize( int type, int size )
{
	STMDATA *stm;
	if ( stm_cur >= stm_max ) throw HSPERR_STACK_OVERFLOW;
	stm = &mem_stm[ stm_cur ];
	stm->type = type;
	StackAlloc( stm, size );
	stm_cur++;
	return (void *)stm->ptr;
}

void StackPushi( int val )
{
	STMDATA *stm;
	if ( stm_cur >= stm_max ) throw HSPERR_STACK_OVERFLOW;
	stm = &mem_stm[ stm_cur ];
	stm->type = HSPVAR_FLAG_INT;
	stm->mode = STMMODE_SELF;
	stm->ptr = (char *)&(stm->ival);
	stm->ival = val;
	stm_cur++;
}

void StackPop( void )
{
	if ( stm_cur <= 0 ) throw HSPERR_UNKNOWN_CODE;
	stm_cur--;
	if ( mem_stm[ stm_cur ].mode ) {
		free( mem_stm[ stm_cur ].ptr );
	}
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2019 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <range/v3/all.hpp>
#include <tuple>
#include <vcf2multialign/check_ploidy.hh>
#include <vcf2multialign/preprocess/preprocess_variants.hh>
#include <vcf2multialign/preprocess/variant_preprocessor.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/variant_format.hh>

namespace lb	= libbio;
namespace v2m	= vcf2multialign;

namespace {
	std::tuple <std::size_t, std::uint8_t> check_ploidy(lb::vcf_reader &vcf_reader)
	{
		v2m::ploidy_map ploidy_map;
		v2m::check_ploidy(vcf_reader, ploidy_map);

		auto const donor_count(ploidy_map.size());
		auto const ploidy(ploidy_map.begin()->second);

		bool can_continue(true);
		for (auto const [sample_no, sample_ploidy] : ploidy_map)
		{
			if (sample_ploidy != ploidy)
			{
				std::cerr << "ERROR: Ploidy for sample " << sample_no << " was " << sample_ploidy << ", expected " << ploidy << ".\n";
				can_continue = false;
			}
		}

		if (!can_continue)
			libbio_fail("Varying ploidy is not currently supported.");

		return std::tuple <std::size_t, std::uint8_t>(donor_count, ploidy);
	}

	template <typename t_map, typename t_key, typename t_ptr_value>
	void add_to_map(t_map &map, t_key const &key, t_ptr_value const ptr_value)
	{
		map.emplace(
			std::piecewise_construct,
			std::forward_as_tuple(key),
			std::forward_as_tuple(ptr_value)
		);
	}
}

namespace vcf2multialign {

	void preprocess_variants(
		char const *reference_path,
		char const *variants_path,
		char const *output_variants_path,
		char const *reference_seq_name,
		char const *chr_name,
		std::vector <std::string> const &field_names_for_filter_if_set,
		bool const should_overwrite_files
	)
	{
		vector_type reference;
		lb::file_ostream output_vcf_stream;

		// Open the files.
		{
			auto const mode(lb::make_writing_open_mode({
				lb::writing_open_mode::CREATE,
				(should_overwrite_files ? lb::writing_open_mode::OVERWRITE : lb::writing_open_mode::NONE)
			}));
			lb::open_file_for_writing(output_variants_path, output_vcf_stream, mode);
		}

		lb::mmap_handle <char> vcf_handle;
		vcf_handle.open(variants_path);

		lb::mmap_handle <char> ref_handle;
		ref_handle.open(reference_path);

		// Read the input FASTA.
		read_single_fasta_seq(ref_handle, reference, reference_seq_name);

		// Create a VCF reader.
		lb::vcf_mmap_input vcf_input(vcf_handle);
		lb::vcf_reader reader(vcf_input);
		lb::add_reserved_genotype_keys(reader.genotype_fields());

		{
			auto &info_fields(reader.info_fields());
			lb::add_reserved_info_keys(info_fields);

			// Add some fields used in 1000G.
			add_to_map(info_fields, "CIPOS",	new vcf_info_field_cipos());
			add_to_map(info_fields, "CIEND",	new vcf_info_field_ciend());
			add_to_map(info_fields, "SVLEN",	new vcf_info_field_svlen());
			add_to_map(info_fields, "SVTYPE",	new vcf_info_field_svtype());
		}

		// Parse.
		reader.set_parsed_fields(lb::vcf_field::ALL);
		reader.set_input(vcf_input);
		reader.fill_buffer();
		reader.read_header();

		// Check the ploidy.
		ploidy_map ploidy;
		check_ploidy(reader, ploidy);
		auto const donor_count(ploidy.size());
		if (!donor_count)
		{
			std::cerr << "WARNING: No donors found." << std::endl;
			return;
		}
		auto const chr_count(ploidy.begin()->second);

		// Process and output the variants.
		variant_preprocessor processor(reader, output_vcf_stream, reference, chr_name, donor_count, chr_count);
		processor.process_and_output(field_names_for_filter_if_set);
	}
}
<commit_msg>Set the variant format properly<commit_after>/*
 * Copyright (c) 2019 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <range/v3/all.hpp>
#include <tuple>
#include <vcf2multialign/check_ploidy.hh>
#include <vcf2multialign/preprocess/preprocess_variants.hh>
#include <vcf2multialign/preprocess/variant_preprocessor.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/variant_format.hh>

namespace lb	= libbio;
namespace v2m	= vcf2multialign;

namespace {
	std::tuple <std::size_t, std::uint8_t> check_ploidy(lb::vcf_reader &vcf_reader)
	{
		v2m::ploidy_map ploidy_map;
		v2m::check_ploidy(vcf_reader, ploidy_map);

		auto const donor_count(ploidy_map.size());
		auto const ploidy(ploidy_map.begin()->second);

		bool can_continue(true);
		for (auto const [sample_no, sample_ploidy] : ploidy_map)
		{
			if (sample_ploidy != ploidy)
			{
				std::cerr << "ERROR: Ploidy for sample " << sample_no << " was " << sample_ploidy << ", expected " << ploidy << ".\n";
				can_continue = false;
			}
		}

		if (!can_continue)
			libbio_fail("Varying ploidy is not currently supported.");

		return std::tuple <std::size_t, std::uint8_t>(donor_count, ploidy);
	}

	template <typename t_map, typename t_key, typename t_ptr_value>
	void add_to_map(t_map &map, t_key const &key, t_ptr_value const ptr_value)
	{
		map.emplace(
			std::piecewise_construct,
			std::forward_as_tuple(key),
			std::forward_as_tuple(ptr_value)
		);
	}
}

namespace vcf2multialign {

	void preprocess_variants(
		char const *reference_path,
		char const *variants_path,
		char const *output_variants_path,
		char const *reference_seq_name,
		char const *chr_name,
		std::vector <std::string> const &field_names_for_filter_if_set,
		bool const should_overwrite_files
	)
	{
		vector_type reference;
		lb::file_ostream output_vcf_stream;

		// Open the files.
		{
			auto const mode(lb::make_writing_open_mode({
				lb::writing_open_mode::CREATE,
				(should_overwrite_files ? lb::writing_open_mode::OVERWRITE : lb::writing_open_mode::NONE)
			}));
			lb::open_file_for_writing(output_variants_path, output_vcf_stream, mode);
		}

		lb::mmap_handle <char> vcf_handle;
		vcf_handle.open(variants_path);

		lb::mmap_handle <char> ref_handle;
		ref_handle.open(reference_path);

		// Read the input FASTA.
		read_single_fasta_seq(ref_handle, reference, reference_seq_name);

		// Create a VCF reader.
		lb::vcf_mmap_input vcf_input(vcf_handle);
		lb::vcf_reader reader(vcf_input);
		lb::add_reserved_genotype_keys(reader.genotype_fields());

		{
			auto &info_fields(reader.info_fields());
			lb::add_reserved_info_keys(info_fields);

			// Add some fields used in 1000G.
			add_to_map(info_fields, "CIPOS",	new vcf_info_field_cipos());
			add_to_map(info_fields, "CIEND",	new vcf_info_field_ciend());
			add_to_map(info_fields, "SVLEN",	new vcf_info_field_svlen());
			add_to_map(info_fields, "SVTYPE",	new vcf_info_field_svtype());
		}

		reader.set_variant_format(new variant_format());

		// Parse.
		reader.set_parsed_fields(lb::vcf_field::ALL);
		reader.set_input(vcf_input);
		reader.fill_buffer();
		reader.read_header();

		// Check the ploidy.
		ploidy_map ploidy;
		check_ploidy(reader, ploidy);
		auto const donor_count(ploidy.size());
		if (!donor_count)
		{
			std::cerr << "WARNING: No donors found." << std::endl;
			return;
		}
		auto const chr_count(ploidy.begin()->second);

		// Process and output the variants.
		variant_preprocessor processor(reader, output_vcf_stream, reference, chr_name, donor_count, chr_count);
		processor.process_and_output(field_names_for_filter_if_set);
	}
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//mapnik
#include <mapnik/debug.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/text/line_layout.hpp>
#include <mapnik/text/placements/base.hpp>
#include <mapnik/text/text_layout.hpp>
#include <mapnik/text/glyph_info.hpp>
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/glyph_positions.hpp>
#include <mapnik/text/glyph_bbox.hpp>
#include <mapnik/vertex_cache.hpp>
#include <mapnik/util/math.hpp>

// stl
#include <vector>

namespace mapnik
{

text_upright_e simplify_upright(text_upright_e upright, double angle)
{
    if (upright == UPRIGHT_AUTO)
    {
        return (std::fabs(util::normalize_angle(angle)) > 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT;
    }
    if (upright == UPRIGHT_AUTO_DOWN)
    {
        return (std::fabs(util::normalize_angle(angle)) < 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT;
    }
    if (upright == UPRIGHT_LEFT_ONLY)
    {
        return UPRIGHT_LEFT;
    }
    if (upright == UPRIGHT_RIGHT_ONLY)
    {
        return  UPRIGHT_RIGHT;
    }
    return upright;
}

single_line_layout::single_line_layout(params_type const & params)
    : params_(params),
      collision_cache_insert_(parse_collision_detector_keys(
          params.get_optional<std::string, keys::collision_cache_insert>()))
{
}

bool single_line_layout::try_placement(
    text_layout_generator & layout_generator,
    vertex_cache & path)
{
    glyph_positions_ptr glyphs = std::make_unique<glyph_positions>();
    layout_container & layouts = *layout_generator.layouts_;
    evaluated_text_properties const & text_props = layout_generator.get_text_props();
    detector_type & detector = layout_generator.detector_;

    if (try_placement(layouts, detector, text_props, path, text_props.upright, *glyphs))
    {
        process_bboxes(detector, layouts, glyphs);
        return true;
    }

    return false;
}

bool single_line_layout::is_reachable(
    detector_type const & detector,
    vertex_cache const & path,
    text_layout const & layout) const
{
    double layout_max_dimension = std::max(layout.width(), layout.height());
    box2d<double> layout_max_box(0, 0, layout_max_dimension * 2, layout_max_dimension * 2);
    pixel_position pos = path.current_position();
    layout_max_box.re_center(pos.x, pos.y);
    return detector.extent().intersects(layout_max_box);
}

bool single_line_layout::try_placement(
    layout_container const & layouts,
    detector_type & detector,
    evaluated_text_properties const & text_props,
    vertex_cache &pp,
    text_upright_e orientation,
    glyph_positions & glyphs)
{
    //
    // IMPORTANT NOTE: See note about coordinate systems in find_point_placement()!
    //

    vertex_cache::scoped_state begin(pp);
    text_upright_e real_orientation = simplify_upright(orientation, pp.angle());
    unsigned upside_down_glyph_count = 0;

    for (auto const& layout_wrapper : layouts)
    {
        text_layout const& layout = layout_wrapper.get();

        if (!is_reachable(detector, pp, layout))
        {
            // Placements beyond collision extent are assumed to be successful.
            return true;
        }

        pixel_position align_offset = layout.alignment_offset();
        pixel_position const& layout_displacement = layout.displacement();
        double sign = (real_orientation == UPRIGHT_LEFT) ? -1 : 1;
        //double offset = 0 - (layout_displacement.y + 0.5 * sign * layout.height());
        double offset = layout_displacement.y - 0.5 * sign * layout.height();
        double adjust_character_spacing = .0;
        double layout_width = layout.width();
        bool adjust = layout.horizontal_alignment() == H_ADJUST;

        if (adjust)
        {
            text_layout::const_iterator longest_line = layout.longest_line();
            if (longest_line != layout.end())
            {
                double longest_line_offset = offset;
                for (text_layout::const_iterator line = layout.begin(); line != longest_line; line++)
                {
                    longest_line_offset += sign * line->height();
                }
                longest_line_offset += sign * longest_line->height() / 2.0;
                vertex_cache const & off_pp = pp.get_offseted(longest_line_offset, sign * layout_width);
                adjust_character_spacing = (off_pp.length() - longest_line->glyphs_width() - 2.0 * halign_adjust_extend) / longest_line->space_count();
                if (adjust_character_spacing < 0)
                {
                    return false;
                }
                layout_width = longest_line->glyphs_width() + longest_line->space_count() * adjust_character_spacing;
            }
        }

        for (auto const& line : layout)
        {
            // Only subtract half the line height here and half at the end because text is automatically
            // centered on the line
            offset += sign * line.height()/2;
            vertex_cache & off_pp = pp.get_offseted(offset, sign * layout_width);
            vertex_cache::scoped_state off_state(off_pp); // TODO: Remove this when a clean implementation in vertex_cache::get_offseted is done
            double line_width = adjust ? (line.glyphs_width() + line.space_count() * adjust_character_spacing) : line.width();

            if (!off_pp.move(sign * layout.jalign_offset(line_width) - align_offset.x)) return false;

            double last_cluster_angle = 999;
            int current_cluster = -1;
            pixel_position cluster_offset;
            double angle = 0;
            rotation rot;
            double last_glyph_spacing = 0.0;
            for (auto const& glyph : line)
            {
                if (current_cluster != static_cast<int>(glyph.char_index))
                {
                    const double cluster_width = (current_cluster < 0) ? 0 : layout.cluster_width(current_cluster);
                    const double distance = sign * (cluster_width + last_glyph_spacing);
                    if (adjust)
                    {
                        if (!off_pp.move(distance)) { return false; }
                        last_glyph_spacing = adjust_character_spacing;
                    }
                    else
                    {
                        if (!off_pp.move_to_distance(distance)) { return false; }
                        last_glyph_spacing = glyph.format.character_spacing * params_.scale_factor;
                    }
                    current_cluster = glyph.char_index;
                    // Only calculate new angle at the start of each cluster!
                    // Y axis is inverted.
                    angle = -util::normalize_angle(off_pp.angle(sign * layout.cluster_width(current_cluster)));
                    rot.init(angle);
                    if ((text_props.max_char_angle_delta > 0) && (last_cluster_angle != 999) &&
                        std::fabs(util::normalize_angle(angle - last_cluster_angle)) > text_props.max_char_angle_delta)
                    {
                        return false;
                    }
                    cluster_offset.clear();
                    last_cluster_angle = angle;
                }

                if (std::abs(angle) > M_PI/2)
                {
                    ++upside_down_glyph_count;
                }

                pixel_position pos = off_pp.current_position() + cluster_offset;
                // Center the text on the line
                double char_height = line.max_char_height();
                pos.y = -pos.y - char_height/2.0*rot.cos;
                pos.x =  pos.x + char_height/2.0*rot.sin;

                cluster_offset.x += rot.cos * glyph.advance;
                cluster_offset.y -= rot.sin * glyph.advance;

                box2d<double> bbox = get_bbox(layout, glyph, pos, rot);
                if (collision(detector, text_props, bbox, layouts.text())) return false;
                glyphs.emplace_back(glyph, pos, rot, bbox);
            }
            // See comment above
            offset += sign * line.height()/2;
        }
    }

    if (upside_down_glyph_count > static_cast<unsigned>(layouts.text().length() / 2))
    {
        if (orientation == UPRIGHT_AUTO)
        {
            // Try again with opposite orientation
            begin.restore();
            glyphs.clear();
            return try_placement(layouts, detector, text_props, pp,
                real_orientation == UPRIGHT_RIGHT ? UPRIGHT_LEFT : UPRIGHT_RIGHT, glyphs);
        }
        // upright==left-only or right-only and more than 50% of characters upside down => no placement
        else if (orientation == UPRIGHT_LEFT_ONLY || orientation == UPRIGHT_RIGHT_ONLY)
        {
            return false;
        }
    }
    else if (orientation == UPRIGHT_AUTO_DOWN)
    {
        // Try again with opposite orientation
        begin.restore();
        glyphs.clear();
        return try_placement(layouts, detector, text_props, pp,
            real_orientation == UPRIGHT_RIGHT ? UPRIGHT_LEFT : UPRIGHT_RIGHT,
            glyphs);
    }

    return true;
}

void single_line_layout::process_bboxes(
    detector_type & detector,
    layout_container & layouts,
    glyph_positions_ptr & glyphs)
{
    bool in_canvas = false;
    for (auto const & glyph_pos : *glyphs)
    {
        box2d<double> bbox(glyph_pos.bbox);
        detector.insert(bbox, layouts.text(), collision_cache_insert_);

        double halo_radius = glyph_pos.glyph.format.halo_radius * params_.scale_factor;
        bbox.pad(halo_radius);

        in_canvas |= params_.dims.intersects(bbox);
    }

    // do not render text off the canvas
    // TODO: throw away single glyphs earlier?
    if (in_canvas)
    {
        layouts.placements_.emplace_back(std::move(glyphs));
    }
}

bool single_line_layout::collision(
    detector_type & detector,
    evaluated_text_properties const & text_props,
    const box2d<double> &box,
    const value_unicode_string &repeat_key) const
{
    double margin = text_props.margin * params_.scale_factor;
    double repeat_distance = (text_props.repeat_distance != 0 ? text_props.repeat_distance : text_props.minimum_distance) * params_.scale_factor;
    return (text_props.avoid_edges && !params_.dims.contains(box))
        ||
        (text_props.minimum_padding > 0 &&
         !params_.dims.contains(box + (params_.scale_factor * text_props.minimum_padding)))
        ||
        (!text_props.allow_overlap &&
         ((repeat_key.length() == 0 && !detector.has_placement(box, margin, text_props.collision_cache_detect))
          ||
          (repeat_key.length() > 0 && !detector.has_placement(box, margin, repeat_key, repeat_distance, text_props.collision_cache_detect))));
}

}// ns mapnik
<commit_msg>Fix 'is_reachable' optimization<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//mapnik
#include <mapnik/debug.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/text/line_layout.hpp>
#include <mapnik/text/placements/base.hpp>
#include <mapnik/text/text_layout.hpp>
#include <mapnik/text/glyph_info.hpp>
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/glyph_positions.hpp>
#include <mapnik/text/glyph_bbox.hpp>
#include <mapnik/vertex_cache.hpp>
#include <mapnik/util/math.hpp>

// stl
#include <vector>

namespace mapnik
{

text_upright_e simplify_upright(text_upright_e upright, double angle)
{
    if (upright == UPRIGHT_AUTO)
    {
        return (std::fabs(util::normalize_angle(angle)) > 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT;
    }
    if (upright == UPRIGHT_AUTO_DOWN)
    {
        return (std::fabs(util::normalize_angle(angle)) < 0.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT;
    }
    if (upright == UPRIGHT_LEFT_ONLY)
    {
        return UPRIGHT_LEFT;
    }
    if (upright == UPRIGHT_RIGHT_ONLY)
    {
        return  UPRIGHT_RIGHT;
    }
    return upright;
}

single_line_layout::single_line_layout(params_type const & params)
    : params_(params),
      collision_cache_insert_(parse_collision_detector_keys(
          params.get_optional<std::string, keys::collision_cache_insert>()))
{
}

bool single_line_layout::try_placement(
    text_layout_generator & layout_generator,
    vertex_cache & path)
{
    glyph_positions_ptr glyphs = std::make_unique<glyph_positions>();
    layout_container & layouts = *layout_generator.layouts_;
    evaluated_text_properties const & text_props = layout_generator.get_text_props();
    detector_type & detector = layout_generator.detector_;

    if (try_placement(layouts, detector, text_props, path, text_props.upright, *glyphs))
    {
        process_bboxes(detector, layouts, glyphs);
        return true;
    }

    return false;
}

bool single_line_layout::is_reachable(
    detector_type const & detector,
    vertex_cache const & path,
    text_layout const & layout) const
{
    // We are not able to decide with haling=adjust
    if (layout.horizontal_alignment() == H_ADJUST)
    {
        return true;
    }
    double layout_max_dimension = std::max(layout.width(), layout.height());
    box2d<double> layout_max_box(0, 0, layout_max_dimension * 2, layout_max_dimension * 2);
    pixel_position pos = path.current_position();
    layout_max_box.re_center(pos.x, pos.y);
    return detector.extent().intersects(layout_max_box);
}

bool single_line_layout::try_placement(
    layout_container const & layouts,
    detector_type & detector,
    evaluated_text_properties const & text_props,
    vertex_cache &pp,
    text_upright_e orientation,
    glyph_positions & glyphs)
{
    //
    // IMPORTANT NOTE: See note about coordinate systems in find_point_placement()!
    //

    vertex_cache::scoped_state begin(pp);
    text_upright_e real_orientation = simplify_upright(orientation, pp.angle());
    unsigned upside_down_glyph_count = 0;

    for (auto const& layout_wrapper : layouts)
    {
        text_layout const& layout = layout_wrapper.get();

        if (!is_reachable(detector, pp, layout))
        {
            // Placements beyond collision extent are assumed to be successful.
            return true;
        }

        pixel_position align_offset = layout.alignment_offset();
        pixel_position const& layout_displacement = layout.displacement();
        double sign = (real_orientation == UPRIGHT_LEFT) ? -1 : 1;
        //double offset = 0 - (layout_displacement.y + 0.5 * sign * layout.height());
        double offset = layout_displacement.y - 0.5 * sign * layout.height();
        double adjust_character_spacing = .0;
        double layout_width = layout.width();
        bool adjust = layout.horizontal_alignment() == H_ADJUST;

        if (adjust)
        {
            text_layout::const_iterator longest_line = layout.longest_line();
            if (longest_line != layout.end())
            {
                double longest_line_offset = offset;
                for (text_layout::const_iterator line = layout.begin(); line != longest_line; line++)
                {
                    longest_line_offset += sign * line->height();
                }
                longest_line_offset += sign * longest_line->height() / 2.0;
                vertex_cache const & off_pp = pp.get_offseted(longest_line_offset, sign * layout_width);
                adjust_character_spacing = (off_pp.length() - longest_line->glyphs_width() - 2.0 * halign_adjust_extend) / longest_line->space_count();
                if (adjust_character_spacing < 0)
                {
                    return false;
                }
                layout_width = longest_line->glyphs_width() + longest_line->space_count() * adjust_character_spacing;
            }
        }

        for (auto const& line : layout)
        {
            // Only subtract half the line height here and half at the end because text is automatically
            // centered on the line
            offset += sign * line.height()/2;
            vertex_cache & off_pp = pp.get_offseted(offset, sign * layout_width);
            vertex_cache::scoped_state off_state(off_pp); // TODO: Remove this when a clean implementation in vertex_cache::get_offseted is done
            double line_width = adjust ? (line.glyphs_width() + line.space_count() * adjust_character_spacing) : line.width();

            if (!off_pp.move(sign * layout.jalign_offset(line_width) - align_offset.x)) return false;

            double last_cluster_angle = 999;
            int current_cluster = -1;
            pixel_position cluster_offset;
            double angle = 0;
            rotation rot;
            double last_glyph_spacing = 0.0;
            for (auto const& glyph : line)
            {
                if (current_cluster != static_cast<int>(glyph.char_index))
                {
                    const double cluster_width = (current_cluster < 0) ? 0 : layout.cluster_width(current_cluster);
                    const double distance = sign * (cluster_width + last_glyph_spacing);
                    if (adjust)
                    {
                        if (!off_pp.move(distance)) { return false; }
                        last_glyph_spacing = adjust_character_spacing;
                    }
                    else
                    {
                        if (!off_pp.move_to_distance(distance)) { return false; }
                        last_glyph_spacing = glyph.format.character_spacing * params_.scale_factor;
                    }
                    current_cluster = glyph.char_index;
                    // Only calculate new angle at the start of each cluster!
                    // Y axis is inverted.
                    angle = -util::normalize_angle(off_pp.angle(sign * layout.cluster_width(current_cluster)));
                    rot.init(angle);
                    if ((text_props.max_char_angle_delta > 0) && (last_cluster_angle != 999) &&
                        std::fabs(util::normalize_angle(angle - last_cluster_angle)) > text_props.max_char_angle_delta)
                    {
                        return false;
                    }
                    cluster_offset.clear();
                    last_cluster_angle = angle;
                }

                if (std::abs(angle) > M_PI/2)
                {
                    ++upside_down_glyph_count;
                }

                pixel_position pos = off_pp.current_position() + cluster_offset;
                // Center the text on the line
                double char_height = line.max_char_height();
                pos.y = -pos.y - char_height/2.0*rot.cos;
                pos.x =  pos.x + char_height/2.0*rot.sin;

                cluster_offset.x += rot.cos * glyph.advance;
                cluster_offset.y -= rot.sin * glyph.advance;

                box2d<double> bbox = get_bbox(layout, glyph, pos, rot);
                if (collision(detector, text_props, bbox, layouts.text())) return false;
                glyphs.emplace_back(glyph, pos, rot, bbox);
            }
            // See comment above
            offset += sign * line.height()/2;
        }
    }

    if (upside_down_glyph_count > static_cast<unsigned>(layouts.text().length() / 2))
    {
        if (orientation == UPRIGHT_AUTO)
        {
            // Try again with opposite orientation
            begin.restore();
            glyphs.clear();
            return try_placement(layouts, detector, text_props, pp,
                real_orientation == UPRIGHT_RIGHT ? UPRIGHT_LEFT : UPRIGHT_RIGHT, glyphs);
        }
        // upright==left-only or right-only and more than 50% of characters upside down => no placement
        else if (orientation == UPRIGHT_LEFT_ONLY || orientation == UPRIGHT_RIGHT_ONLY)
        {
            return false;
        }
    }
    else if (orientation == UPRIGHT_AUTO_DOWN)
    {
        // Try again with opposite orientation
        begin.restore();
        glyphs.clear();
        return try_placement(layouts, detector, text_props, pp,
            real_orientation == UPRIGHT_RIGHT ? UPRIGHT_LEFT : UPRIGHT_RIGHT,
            glyphs);
    }

    return true;
}

void single_line_layout::process_bboxes(
    detector_type & detector,
    layout_container & layouts,
    glyph_positions_ptr & glyphs)
{
    bool in_canvas = false;
    for (auto const & glyph_pos : *glyphs)
    {
        box2d<double> bbox(glyph_pos.bbox);
        detector.insert(bbox, layouts.text(), collision_cache_insert_);

        double halo_radius = glyph_pos.glyph.format.halo_radius * params_.scale_factor;
        bbox.pad(halo_radius);

        in_canvas |= params_.dims.intersects(bbox);
    }

    // do not render text off the canvas
    // TODO: throw away single glyphs earlier?
    if (in_canvas)
    {
        layouts.placements_.emplace_back(std::move(glyphs));
    }
}

bool single_line_layout::collision(
    detector_type & detector,
    evaluated_text_properties const & text_props,
    const box2d<double> &box,
    const value_unicode_string &repeat_key) const
{
    double margin = text_props.margin * params_.scale_factor;
    double repeat_distance = (text_props.repeat_distance != 0 ? text_props.repeat_distance : text_props.minimum_distance) * params_.scale_factor;
    return (text_props.avoid_edges && !params_.dims.contains(box))
        ||
        (text_props.minimum_padding > 0 &&
         !params_.dims.contains(box + (params_.scale_factor * text_props.minimum_padding)))
        ||
        (!text_props.allow_overlap &&
         ((repeat_key.length() == 0 && !detector.has_placement(box, margin, text_props.collision_cache_detect))
          ||
          (repeat_key.length() > 0 && !detector.has_placement(box, margin, repeat_key, repeat_distance, text_props.collision_cache_detect))));
}

}// ns mapnik
<|endoftext|>


<commit_before>// arm-poky-linux-gnueabi-gcc -lopencv_video -lopencv_core -lopencv_highgui -lopencv_imgproc -lstdc++ -lpthread -shared-libgcc opencv.cpp -o opencv

#include "evision.h"
#include "tracer.h"
#include "gpio.h"

// Global variables
GPIO pwm_right(1, "out"), pwm_left(3, "out"); // led_right(2 , "out");
GPIO led_front(5, "out"), led_R(4, "out"), start(7 ,"out"); // 0,2,6 bulit
int high_right = 600, high_left = 600, period = 20000; //PWM high time in us
int top_edge = 50, servo_offset = 0, road_offset = 0;

// GUI globals
cv::Mat guiframe;
bool new_frame = false;
bool running = true;

// Window titles
char main_window_name[] = "Lightning Asystant :: Team eVision";
char settings_window_name[] = "Settings :: Team eVision";

// Settings variables
int settings_show_step = 0;
int settings_contrast = 0;
int settings_blur = 1;
int settings_threshold = 128;
int settings_servo_offset = 500;
int settings_road_approx = 5;
int settings_middle_line = 240;

// Graphics
std::vector<std::vector<cv::Point>> contours;

//Functions declaration
void pwm_servo_right(int);
void pwm_servo_left(int);
int car_position(int);
int obstacle_position(int);

int main(int argc, char** argv)
{
    pthread_t processing_thread;
    long time_old;
    int fps_counter = 0;
    int gui_key;

	// for cpu affinity
	cpu_set_t cpuset;
	int cpu = 0;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    // process priority
    setpriority(PRIO_PROCESS, 0, -20);

    // GUI setup
	cv::namedWindow(main_window_name);

	// Setup window
	cv::namedWindow(settings_window_name);
	cv::createTrackbar("Show Step   ", settings_window_name, &settings_show_step, LAST_STEP-1);
	cv::createTrackbar("Contrast    ", settings_window_name, &settings_contrast, 1);
	cv::createTrackbar("Mean Blur   ", settings_window_name, &settings_blur, 1);
	cv::createTrackbar("Threshold   ", settings_window_name, &settings_threshold, 255);
	cv::createTrackbar("Road Approx ", settings_window_name, &settings_road_approx, 30);
	cv::createTrackbar("Middle Line ", settings_window_name, &settings_middle_line, 320);
	cv::createTrackbar("Servo Offset", settings_window_name, &settings_servo_offset, 1000);
	cv::createTrackbar("Servo Right ", settings_window_name, &high_right, 1500);
	cv::createTrackbar("Servo Left  ", settings_window_name, &high_left, 1500);

	pthread_create(&processing_thread, NULL, processing_thread_function, NULL);
	//pthread_create(&pwm_thread, NULL, pwm_thread_function, NULL);

    while(running){

    	while(!new_frame){ } // loop

		cv::imshow(main_window_name, guiframe);

		// calculate fps
		if(time(NULL) != time_old){
			add_info(fps_counter);
			fps_counter = 1;
			time_old = time(NULL);
		} else {
			fps_counter++;
		}

		new_frame = 0;

		gui_key = cv::waitKey(5);
		if(gui_key >= 0) {
			gui_key %= 0xFF;

			// ESC
			if((gui_key == 43) || (gui_key == 27)){
				led_front.low();
				led_R.low();
				running = false;
			} else if((gui_key == 48) || (gui_key == 32)) {
				start.high(); // 1 = start/stop
				usleep(50000);
				start.low();
			} else if((gui_key == 50) || (gui_key == 66)) {
				led_front.toggle(); // 2 = faruri
			} else if((gui_key == 51) || (gui_key == 67)) {
				led_R.toggle(); // 3 = far pieton
			} else {
				std::cout << gui_key << std::endl;
			}
		}
    }

	pthread_join(processing_thread, NULL);

    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}

void send_frame_to_gui(cv::Mat &frame, int step){
	if((new_frame == 0) && (step == settings_show_step)){
		//cv::pyrUp(frame, guiframe);
		frame.copyTo(guiframe);
		new_frame = 1;
	}
}

bool contour_area(int a, int b){
	return cv::contourArea(contours[a]) > cv::contourArea(contours[b]);
}

bool get_obstacle(
	int parent,
	std::vector<std::vector<cv::Point>> contours,
	std::vector<cv::Vec4i> hierarchy,
	cv::Rect &obstacle){

	int start = hierarchy[parent][2];
	int closest = -1;
	bool found = false;

	while(start > 0){

		if(closest == -1){
			closest = start;
			found = true;
		} else if(cv::boundingRect(contours[start]).y > cv::boundingRect(contours[closest]).y){
			closest = start;
		}

		start = hierarchy[start][0];
	}

	if(found){
		obstacle = cv::boundingRect(contours[closest]);
	}

	return found;
}

void draw_obstacles(cv::Mat &threshold_frame, cv::Mat &cam_frame){
	std::vector<std::vector<cv::Point>> road(2);
	std::vector<cv::Vec4i> hierarchy;

	cv::findContours(threshold_frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
	if(contours.size() > 1){

		// create index vector
		std::vector<int> contour_indexes(contours.size());

		for(unsigned int i = 0; i < contours.size(); i++){
			contour_indexes[i] = i;
		}

		// sorting index vector acording to controur area
		std::sort(contour_indexes.begin(), contour_indexes.end(), contour_area);

		cv::approxPolyDP(cv::Mat(contours[contour_indexes[0]]), road[0], settings_road_approx, true);
		cv::approxPolyDP(cv::Mat(contours[contour_indexes[1]]), road[1], settings_road_approx, true);

		// validate road detection
		int road_edge = -1;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y > 235) && (road_edge == -1)){
				road_edge = road[0][i].x;

			} else if((road[0][i].y > 235) && (road[0][i].x < road_edge)){

				road_edge = road[0][i].x;
			}
		}

		if(road_edge < 0)
			return ;

		for(unsigned int i = 0; i < road[1].size(); ++i){
			if((road[1][i].y > 235) && (road[1][i].x > road_edge)){

				// wrong detection
				return;
			}
		}

		// paint road area
		cv::drawContours(cam_frame, road, 0, cv::Scalar(0, 255 ,0), 2);
		cv::drawContours(cam_frame, road, 1, cv::Scalar(255, 0, 0), 2);

		// get road offset
		// reference point is the left most point from the top edge of road contour
		int new_road_offset = 600;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y == top_edge) && (road[0][i].x < new_road_offset)){
				new_road_offset = road[0][i].x;
			}
		}

		if((new_road_offset > 50) && (new_road_offset < 250)){
			road_offset = new_road_offset;
		}

		//std::cout << road_offset << std::endl;

		cv::Rect obstacle;
		if(get_obstacle(contour_indexes[0], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(0, 0, 255));
			//std::cout << cv::Point(obstacle.x + (obstacle.width / 2), obstacle.y + (obstacle.height / 2)) << std::endl;
			h_r = high_right + servo_offset + road_offset + car_position(obstacle.y + (obstacle.height / 2));//!!!!
			pwm_servo_right(h_r);
		}

		if(get_obstacle(contour_indexes[1], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(255, 0, 255));

			h_l = high_left + servo_offset + road_offset + obstacle_position(0);//!!!!
   			pwm_servo_left(h_l);
		}

		cv::line(cam_frame, cv::Point(settings_middle_line, 320), cv::Point(settings_middle_line, top_edge), cv::Scalar(0, 255, 255));
	}
}

void *processing_thread_function(void* unsused)
{
	cv::VideoCapture 	cap(0); // camera interface
    cv::Mat 			frame, cam_frame, bw_frame, blur_frame, contrast_frame;
    cv::Mat				threshold_frame, canny_frame, contour_frame;
    Tracer				processing_tracer;

    // for cpu affinity
	cpu_set_t cpuset;
	int cpu = 1, h_r, h_l;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    if(!cap.isOpened())  // check if we succeeded
    {
        std::cout << "Could not open default video device" << std::endl;
        pthread_exit(NULL);

    }

   	while(running) {
		if( !cap.read(frame) ){
			std::cout << "Camera was disconected";
			break;
		}

		cv::pyrDown(frame, cam_frame);
		send_frame_to_gui(cam_frame, SENSOR_IMAGE);
		processing_tracer.start();

		// All processing are done on gray image
		cv::cvtColor(cam_frame, bw_frame, CV_BGR2GRAY);
		processing_tracer.event("Convert to Gray");
		send_frame_to_gui(bw_frame, GRAY_IMAGE);

		// Increase contrast by distributing color histogram to contain all values
		if(settings_contrast){
			cv::equalizeHist(bw_frame, contrast_frame);
		} else {
			contrast_frame = bw_frame;
		}
		processing_tracer.event("Equalize histogram");
		send_frame_to_gui(contrast_frame, CONTRAST_IMAGE);

		// Apply a special blur filter which preserves edges
		if(settings_blur){
			cv::medianBlur(contrast_frame, blur_frame, 7);
		} else {
			blur_frame = contrast_frame;
		}
		processing_tracer.event("Median blur");
		send_frame_to_gui(blur_frame, BLUR_IMAGE);

		// detect edges using histeresys
		cv::Canny(contrast_frame, canny_frame, 30, 100);
		processing_tracer.event("Edge detection");
		send_frame_to_gui(canny_frame, CANNY_IMAGE);

		// Apply threshhold
		threshold(blur_frame, threshold_frame, settings_threshold, 255, CV_THRESH_BINARY);
		// Disable image top from detection to remove false edges
		cv::rectangle(threshold_frame, cv::Rect(0, 0, 320, top_edge), cv::Scalar(0), CV_FILLED);
		processing_tracer.event("Appling threshold");
		send_frame_to_gui(threshold_frame, THRESHOLD_IMAGE);

		// detect and paint contours
		draw_obstacles(threshold_frame, cam_frame);
		processing_tracer.event("Contour detection");
		send_frame_to_gui(cam_frame, CONTOUR_IMAGE);
	}

	processing_tracer.end();
	pthread_exit(NULL);
}

void pwm_servo_right(int h_r){
	int static local_hr = 0;
	if(abs(h_r - local_hr) > 5){
		local_hr = h_r;
		pwm_right.high();
		usleep(local_hr);
		pwm_right.low();
		usleep(period - local_hr);
	}
}

void pwm_servo_left(int h_l){
	int static local_hl = 0;
	if(abs(h_l - local_hl) > 5){
		local_hl = h_l;
		pwm_left.high();
		usleep(local_hl);
		pwm_left.low();
		usleep(period - local_hl);
	}
}

int obstacle_position(int y_position){
	if(y_position > top_edge){
		return int ( 0.9 * y_position + 15);
	} else {
		return 0;
	}
}

int car_position(int y_position){
	if(y_position > top_edge){
		return 1;
	} else {
		return 0;
	}
}

void add_info(int fps){
	// white canvas
	cv::Mat img_info (25, 320, CV_8UC3, cv::Scalar(255, 255, 255));

	cv::putText(img_info, std::string("FPS: ") + std::to_string(fps), cv::Point(5, 20),
			cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cv::Scalar(0,0,255), 1, CV_AA);

	cv::imshow(settings_window_name, img_info);
}
<commit_msg>removed bug from magic function<commit_after>// arm-poky-linux-gnueabi-gcc -lopencv_video -lopencv_core -lopencv_highgui -lopencv_imgproc -lstdc++ -lpthread -shared-libgcc opencv.cpp -o opencv

#include "evision.h"
#include "tracer.h"
#include "gpio.h"

// Global variables
GPIO pwm_right(1, "out"), pwm_left(3, "out"); // led_right(2 , "out");
GPIO led_front(5, "out"), led_R(4, "out"), start(7 ,"out"); // 0,2,6 bulit
int high_right = 600, high_left = 600, period = 20000; //PWM high time in us
int top_edge = 50, servo_offset = 0, road_offset = 0;

// GUI globals
cv::Mat guiframe;
bool new_frame = false;
bool running = true;

// Window titles
char main_window_name[] = "Lightning Asystant :: Team eVision";
char settings_window_name[] = "Settings :: Team eVision";

// Settings variables
int settings_show_step = 0;
int settings_contrast = 0;
int settings_blur = 1;
int settings_threshold = 128;
int settings_servo_offset = 500;
int settings_road_approx = 5;
int settings_middle_line = 240;

// Graphics
std::vector<std::vector<cv::Point>> contours;

//Functions declaration
void pwm_servo_right(int);
void pwm_servo_left(int);
int car_position(int);
int obstacle_position(int);

int main(int argc, char** argv)
{
    pthread_t processing_thread;
    long time_old;
    int fps_counter = 0;
    int gui_key;

	// for cpu affinity
	cpu_set_t cpuset;
	int cpu = 0;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    // process priority
    setpriority(PRIO_PROCESS, 0, -20);

    // GUI setup
	cv::namedWindow(main_window_name);

	// Setup window
	cv::namedWindow(settings_window_name);
	cv::createTrackbar("Show Step   ", settings_window_name, &settings_show_step, LAST_STEP-1);
	cv::createTrackbar("Contrast    ", settings_window_name, &settings_contrast, 1);
	cv::createTrackbar("Mean Blur   ", settings_window_name, &settings_blur, 1);
	cv::createTrackbar("Threshold   ", settings_window_name, &settings_threshold, 255);
	cv::createTrackbar("Road Approx ", settings_window_name, &settings_road_approx, 30);
	cv::createTrackbar("Middle Line ", settings_window_name, &settings_middle_line, 320);
	cv::createTrackbar("Servo Offset", settings_window_name, &settings_servo_offset, 1000);
	cv::createTrackbar("Servo Right ", settings_window_name, &high_right, 1500);
	cv::createTrackbar("Servo Left  ", settings_window_name, &high_left, 1500);

	pthread_create(&processing_thread, NULL, processing_thread_function, NULL);
	//pthread_create(&pwm_thread, NULL, pwm_thread_function, NULL);

    while(running){

    	while(!new_frame){ } // loop

		cv::imshow(main_window_name, guiframe);

		// calculate fps
		if(time(NULL) != time_old){
			add_info(fps_counter);
			fps_counter = 1;
			time_old = time(NULL);
		} else {
			fps_counter++;
		}

		new_frame = 0;

		gui_key = cv::waitKey(5);
		if(gui_key >= 0) {
			gui_key %= 0xFF;

			// ESC
			if((gui_key == 43) || (gui_key == 27)){
				led_front.low();
				led_R.low();
				running = false;
			} else if((gui_key == 48) || (gui_key == 32)) {
				start.high(); // 1 = start/stop
				usleep(50000);
				start.low();
			} else if((gui_key == 50) || (gui_key == 66)) {
				led_front.toggle(); // 2 = faruri
			} else if((gui_key == 51) || (gui_key == 67)) {
				led_R.toggle(); // 3 = far pieton
			} else {
				std::cout << gui_key << std::endl;
			}
		}
    }

	pthread_join(processing_thread, NULL);

    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}

void send_frame_to_gui(cv::Mat &frame, int step){
	if((new_frame == 0) && (step == settings_show_step)){
		//cv::pyrUp(frame, guiframe);
		frame.copyTo(guiframe);
		new_frame = 1;
	}
}

bool contour_area(int a, int b){
	return cv::contourArea(contours[a]) > cv::contourArea(contours[b]);
}

bool get_obstacle(
	int parent,
	std::vector<std::vector<cv::Point>> contours,
	std::vector<cv::Vec4i> hierarchy,
	cv::Rect &obstacle){

	int start = hierarchy[parent][2];
	int closest = -1;
	bool found = false;

	while(start > 0){

		if(closest == -1){
			closest = start;
			found = true;
		} else if(cv::boundingRect(contours[start]).y > cv::boundingRect(contours[closest]).y){
			closest = start;
		}

		start = hierarchy[start][0];
	}

	if(found){
		obstacle = cv::boundingRect(contours[closest]);
	}

	return found;
}

void draw_obstacles(cv::Mat &threshold_frame, cv::Mat &cam_frame){
	std::vector<std::vector<cv::Point>> road(2);
	std::vector<cv::Vec4i> hierarchy;

	cv::findContours(threshold_frame, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
	if(contours.size() > 1){

		// create index vector
		std::vector<int> contour_indexes(contours.size());

		for(unsigned int i = 0; i < contours.size(); i++){
			contour_indexes[i] = i;
		}

		// sorting index vector acording to controur area
		std::sort(contour_indexes.begin(), contour_indexes.end(), contour_area);

		cv::approxPolyDP(cv::Mat(contours[contour_indexes[0]]), road[0], settings_road_approx, true);
		cv::approxPolyDP(cv::Mat(contours[contour_indexes[1]]), road[1], settings_road_approx, true);

		// validate road detection
		int road_edge = -1;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y > 235) && (road_edge == -1)){
				road_edge = road[0][i].x;

			} else if((road[0][i].y > 235) && (road[0][i].x < road_edge)){

				road_edge = road[0][i].x;
			}
		}

		if(road_edge < 0)
			return ;

		for(unsigned int i = 0; i < road[1].size(); ++i){
			if((road[1][i].y > 235) && (road[1][i].x > road_edge)){

				// wrong detection
				return;
			}
		}

		// paint road area
		cv::drawContours(cam_frame, road, 0, cv::Scalar(0, 255 ,0), 2);
		cv::drawContours(cam_frame, road, 1, cv::Scalar(255, 0, 0), 2);

		// get road offset
		// reference point is the left most point from the top edge of road contour
		int new_road_offset = 600;
		for(unsigned int i = 0; i < road[0].size(); ++i){
			if((road[0][i].y == top_edge) && (road[0][i].x < new_road_offset)){
				new_road_offset = road[0][i].x;
			}
		}

		if((new_road_offset > 50) && (new_road_offset < 250)){
			road_offset = new_road_offset;
		}

		//std::cout << road_offset << std::endl;

		cv::Rect obstacle;
		if(get_obstacle(contour_indexes[0], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(0, 0, 255));
			//std::cout << cv::Point(obstacle.x + (obstacle.width / 2), obstacle.y + (obstacle.height / 2)) << std::endl;
			pwm_servo_right(high_right + servo_offset + road_offset + car_position(obstacle.y + (obstacle.height / 2)));
		}

		if(get_obstacle(contour_indexes[1], contours, hierarchy, obstacle)){
			cv::rectangle(cam_frame, obstacle, cv::Scalar(255, 0, 255));

   			pwm_servo_left(high_left + servo_offset + road_offset + obstacle_position(0));
		}

		cv::line(cam_frame, cv::Point(settings_middle_line, 320), cv::Point(settings_middle_line, top_edge), cv::Scalar(0, 255, 255));
	}
}

void *processing_thread_function(void* unsused)
{
	cv::VideoCapture 	cap(0); // camera interface
    cv::Mat 			frame, cam_frame, bw_frame, blur_frame, contrast_frame;
    cv::Mat				threshold_frame, canny_frame, contour_frame;
    Tracer				processing_tracer;

    // for cpu affinity
	cpu_set_t cpuset;
	int cpu = 1;

	CPU_ZERO(&cpuset);       //clears the cpuset
	CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

    if(!cap.isOpened())  // check if we succeeded
    {
        std::cout << "Could not open default video device" << std::endl;
        pthread_exit(NULL);

    }

   	while(running) {
		if( !cap.read(frame) ){
			std::cout << "Camera was disconected";
			break;
		}

		cv::pyrDown(frame, cam_frame);
		send_frame_to_gui(cam_frame, SENSOR_IMAGE);
		processing_tracer.start();

		// All processing are done on gray image
		cv::cvtColor(cam_frame, bw_frame, CV_BGR2GRAY);
		processing_tracer.event("Convert to Gray");
		send_frame_to_gui(bw_frame, GRAY_IMAGE);

		// Increase contrast by distributing color histogram to contain all values
		if(settings_contrast){
			cv::equalizeHist(bw_frame, contrast_frame);
		} else {
			contrast_frame = bw_frame;
		}
		processing_tracer.event("Equalize histogram");
		send_frame_to_gui(contrast_frame, CONTRAST_IMAGE);

		// Apply a special blur filter which preserves edges
		if(settings_blur){
			cv::medianBlur(contrast_frame, blur_frame, 7);
		} else {
			blur_frame = contrast_frame;
		}
		processing_tracer.event("Median blur");
		send_frame_to_gui(blur_frame, BLUR_IMAGE);

		// detect edges using histeresys
		cv::Canny(contrast_frame, canny_frame, 30, 100);
		processing_tracer.event("Edge detection");
		send_frame_to_gui(canny_frame, CANNY_IMAGE);

		// Apply threshhold
		threshold(blur_frame, threshold_frame, settings_threshold, 255, CV_THRESH_BINARY);
		// Disable image top from detection to remove false edges
		cv::rectangle(threshold_frame, cv::Rect(0, 0, 320, top_edge), cv::Scalar(0), CV_FILLED);
		processing_tracer.event("Appling threshold");
		send_frame_to_gui(threshold_frame, THRESHOLD_IMAGE);

		// detect and paint contours
		draw_obstacles(threshold_frame, cam_frame);
		processing_tracer.event("Contour detection");
		send_frame_to_gui(cam_frame, CONTOUR_IMAGE);
	}

	processing_tracer.end();
	pthread_exit(NULL);
}

void pwm_servo_right(int h_r){
	int static local_hr = 0;
	if(abs(h_r - local_hr) > 5){
		local_hr = h_r;
		pwm_right.high();
		usleep(local_hr);
		pwm_right.low();
		usleep(period - local_hr);
	}
}

void pwm_servo_left(int h_l){
	int static local_hl = 0;
	if(abs(h_l - local_hl) > 5){
		local_hl = h_l;
		pwm_left.high();
		usleep(local_hl);
		pwm_left.low();
		usleep(period - local_hl);
	}
}

int obstacle_position(int y_position){
	if(y_position > top_edge){
		return int ( 0.9 * y_position + 15);
	} else {
		return 0;
	}
}

int car_position(int y_position){
	if(y_position > top_edge){
		return 1;
	} else {
		return 0;
	}
}

void add_info(int fps){
	// white canvas
	cv::Mat img_info (25, 320, CV_8UC3, cv::Scalar(255, 255, 255));

	cv::putText(img_info, std::string("FPS: ") + std::to_string(fps), cv::Point(5, 20),
			cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cv::Scalar(0,0,255), 1, CV_AA);

	cv::imshow(settings_window_name, img_info);
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2012 <benemorius@gmail.com>

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

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

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

#include "Callback.h"

Callback::Callback()
{

}

Callback::~Callback()
{
	std::deque<FunctionPointer<void>*>::iterator function = functions.begin();
	std::deque<Timer*>::iterator timer = timers.begin();
	std::deque<uint32_t>::iterator time = times.begin();

	while(function != functions.end())
	{
		delete *function;
		delete * timer;
		++function;
		++timer;
	}
}

void Callback::task()
{
	std::deque<FunctionPointer<void>*>::iterator function = functions.begin();
	std::deque<Timer*>::iterator timer = timers.begin();
	std::deque<uint32_t>::iterator time = times.begin();

	while(function != functions.end())
	{
		if((*timer)->read_ms() >= *time)
		{
			(*function)->call();
			delete *function;
			delete *timer;
			functions.erase(function);
			timers.erase(timer);
			times.erase(time);
			function = functions.begin();
			timer = timers.begin();
			time = times.begin();
		}
		else
		{
			++function;
			++timer;
			++time;
		}
	}
}

<commit_msg>add Callback class WIP<commit_after>/*
    Copyright (c) 2012 <benemorius@gmail.com>

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

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

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

#include "Callback.h"

Callback::Callback()
{

}

Callback::~Callback()
{
	std::deque<FunctionPointer<void>*>::iterator function = functions.begin();
	std::deque<Timer*>::iterator timer = timers.begin();
	std::deque<uint32_t>::iterator time = times.begin();

	while(function != functions.end())
	{
		delete *function;
		delete * timer;
		++function;
		++timer;
	}
}

void Callback::task()
{
	std::deque<FunctionPointer<void>*>::iterator function = functions.begin();
	std::deque<Timer*>::iterator timer = timers.begin();
	std::deque<uint32_t>::iterator time = times.begin();

	while(function != functions.end())
	{
		if((*timer)->read_ms() >= *time)
		{
			FunctionPointer<void>* f = *function;
			Timer* t = *timer;
			functions.erase(function);
			timers.erase(timer);
			times.erase(time);

			f->call();
			delete f;
			delete t;

			function = functions.begin();
			timer = timers.begin();
			time = times.begin();
		}
		else
		{
			++function;
			++timer;
			++time;
		}
	}
}

<|endoftext|>