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

using Info = tuple<ll, ll>;

int main()
{
  int N;
  cin >> N;
  vector<Info> V(N);
  ll A_sum{0LL};
  for (auto i = 0; i < N; i++)
  {
    ll A, B;
    cin >> A >> B;
    V[i] = Info(max(A, B), B);
    A_sum += A;
  }
  sort(V.rbegin(), V.rend());
  vector<ll> C_sum(N + 1);
  C_sum[0] = 0;
  for (auto i = 0; i < N; i++)
  {
    C_sum[i + 1] = C_sum[i] + get<0>(V[i]);
  }
  if (C_sum[N] == A_sum)
  {
    No();
  }
  rational<ll> ans{0, 1};
  for (auto k = 0; k < N; k++)
  {
    ll B_k{get<1>(V[k])};
    ll ok{N}, ng{-1};
    ll tmp_sum{0};
    bool included{false};
    while (abs(ok - ng) > 1)
    {
      ll t{(ok + ng) / 2};
      ll tmp{C_sum[t]};
      if (k < t)
      {
        tmp -= B_k;
      }
      if (tmp + B_k >= A_sum)
      {
        ok = t;
        included = k < t;
        tmp_sum = tmp;
      }
      else
      {
        ng = t;
      }
    }
    rational<ll> r{A_sum - tmp_sum, B_k};
#if DEBUG == 1
    cerr << "k = " << k << ", B_k = " << B_k << ", tmp_sum = " << tmp_sum << ", r = " << r << endl;
#endif
    if (r < 0)
    {
      r = rational<ll>(0);
    }
    ll M{included ? ok + 1 : ok};
    rational<ll> tmp_ans = (N - M - r) / N;
    ch_max(ans, tmp_ans);
  }
  cout << ans.numerator() << " " << ans.denominator() << endl;
}
<commit_msg>tried D2.cpp to 'D'<commit_after>#define DEBUG 1
/**
 * File    : D2.cpp
 * Author  : Kazune Takahashi
 * Created : 11/13/2019, 7:24:07 PM
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <boost/rational.hpp>
using boost::rational;
using namespace std;
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
using ll = long long;
constexpr ll MOD{1000000007LL};
constexpr ll MAX_SIZE{3000010LL};
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{x % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// for C++14
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "0 1" << endl;
  exit(0);
}

using Info = tuple<ll, ll>;

int main()
{
  int N;
  cin >> N;
  vector<Info> V(N);
  ll A_sum{0LL};
  for (auto i = 0; i < N; i++)
  {
    ll A, B;
    cin >> A >> B;
    V[i] = Info(max(A, B), B);
    A_sum += A;
  }
  sort(V.rbegin(), V.rend());
  vector<ll> C_sum(N + 1);
  C_sum[0] = 0;
  for (auto i = 0; i < N; i++)
  {
    C_sum[i + 1] = C_sum[i] + get<0>(V[i]);
  }
  if (C_sum[N] == A_sum)
  {
    No();
  }
  rational<ll> ans{0, 1};
  for (auto k = 0; k < N; k++)
  {
    ll B_k{get<1>(V[k])};
    ll ok{N}, ng{-1};
    ll tmp_sum{0};
    bool included{false};
    while (abs(ok - ng) > 1)
    {
      ll t{(ok + ng) / 2};
      ll tmp{C_sum[t]};
      if (k < t)
      {
        tmp -= B_k;
      }
      if (tmp + B_k >= A_sum)
      {
        ok = t;
        included = k < t;
        tmp_sum = tmp;
      }
      else
      {
        ng = t;
      }
    }
    rational<ll> r{A_sum - tmp_sum, B_k};
#if DEBUG == 1
    cerr << "k = " << k << ", B_k = " << B_k << ", tmp_sum = " << tmp_sum << ", r = " << r << endl;
#endif
    if (r < 0)
    {
      r = rational<ll>(0);
    }
    ll M{included ? ok : ok};
    rational<ll> tmp_ans = (N - M - r) / N;
    ch_max(ans, tmp_ans);
  }
  cout << ans.numerator() << " " << ans.denominator() << endl;
}
<|endoftext|>


<commit_before>#include "texture.h"
#include "stb_image.h"
#include <iostream>
#include <cassert>

std::map<std::string, TextureData*> Texture::s_resourceMap;

TextureData::TextureData(GLenum textureTarget, int width, int height, int numTextures, unsigned char** data, GLfloat* filters, GLenum* attachments)
{
	m_textureID = new GLuint[numTextures];
	m_textureTarget = textureTarget;
	m_numTextures = numTextures;
	m_width = width;
	m_height = height;
	m_frameBuffer = 0;
	m_renderBuffer = 0;

	InitTextures(data, filters);
	InitRenderTargets(attachments);
}

TextureData::~TextureData()
{
	if(*m_textureID) glDeleteTextures(m_numTextures, m_textureID);
	if(m_frameBuffer) glDeleteFramebuffers(1, &m_frameBuffer);
	if(m_renderBuffer) glDeleteRenderbuffers(1, &m_renderBuffer);
	if(m_textureID) delete[] m_textureID;
}

void TextureData::InitTextures(unsigned char** data, GLfloat* filters)
{
	glGenTextures(m_numTextures, m_textureID);
	for(int i = 0; i < m_numTextures; i++)
	{
		glBindTexture(m_textureTarget, m_textureID[i]);

		glTexParameterf(m_textureTarget, GL_TEXTURE_MIN_FILTER, filters[i]);
		glTexParameterf(m_textureTarget, GL_TEXTURE_MAG_FILTER, filters[i]);

		glTexImage2D(m_textureTarget, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data[i]);
	}
}

void TextureData::InitRenderTargets(GLenum* attachments)
{
	if(attachments == 0)
		return;

	GLenum drawBuffers[m_numTextures];
	bool hasDepth = false;

	for(int i = 0; i < m_numTextures; i++)
	{
		if(attachments[i] == GL_DEPTH_ATTACHMENT)
		{
			drawBuffers[i] = GL_NONE;
			hasDepth = true;
		}
		else
			drawBuffers[i] = attachments[i];

		if(attachments[i] == GL_NONE)
			continue;

		if(m_frameBuffer == 0)
		{
			glGenFramebuffers(1, &m_frameBuffer);
			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_frameBuffer);
		}

		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachments[i], m_textureTarget, m_textureID[i], 0);
	}

	if(m_frameBuffer == 0)
		return;

	if(!hasDepth)
	{
		glGenRenderbuffers(1, &m_renderBuffer);
		glBindRenderbuffer(GL_RENDERBUFFER, m_renderBuffer);
		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_width, m_height);
		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_renderBuffer);
	}

	glDrawBuffers(m_numTextures, drawBuffers);

	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
	{
		std::cerr << "Framebuffer creation failed!" << std::endl;
		assert(false);
	}
}

void TextureData::Bind(int textureNum)
{
	glBindTexture(m_textureTarget, m_textureID[textureNum]);
}

void TextureData::BindAsRenderTarget()
{
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_frameBuffer);
	glViewport(0, 0, m_width, m_height);
}

Texture::Texture(const std::string& fileName, GLenum textureTarget, GLfloat filter, GLenum attachment)
{
 	m_fileName = fileName;

	std::map<std::string, TextureData*>::const_iterator it = s_resourceMap.find(fileName);
	if(it != s_resourceMap.end())
	{
		m_textureData = it->second;
		m_textureData->AddReference();
	}
	else
	{
		int x, y, bytesPerPixel;
		unsigned char* data = stbi_load(("./res/textures/" + fileName).c_str(), &x, &y, &bytesPerPixel, 4);

		if(data == NULL)
		{
			std::cerr << "Unable to load texture: " << fileName << std::endl;
		}

		m_textureData = new TextureData(textureTarget, x, y, 1, &data, &filter, &attachment);
		stbi_image_free(data);

		s_resourceMap.insert(std::pair<std::string, TextureData*>(fileName, m_textureData));
	}
}

Texture::Texture(int width, int height, unsigned char* data, GLenum textureTarget, GLfloat filter, GLenum attachment)
{
	m_fileName = "";
	m_textureData = new TextureData(textureTarget, width, height, 1, &data, &filter, &attachment);
}

Texture::~Texture()
{
	if(m_textureData && m_textureData->RemoveReference())
	{
		if(m_fileName.length() > 0)
			s_resourceMap.erase(m_fileName);

		delete m_textureData;
	}
}

void Texture::Bind(unsigned int unit) const
{
	assert(unit >= 0 && unit <= 31);
	glActiveTexture(GL_TEXTURE0 + unit);
	m_textureData->Bind(0);
}

void Texture::BindAsRenderTarget()
{
	m_textureData->BindAsRenderTarget();
}
<commit_msg>Fixed drawBuffer issue<commit_after>#include "texture.h"
#include "stb_image.h"
#include <iostream>
#include <cassert>

std::map<std::string, TextureData*> Texture::s_resourceMap;

TextureData::TextureData(GLenum textureTarget, int width, int height, int numTextures, unsigned char** data, GLfloat* filters, GLenum* attachments)
{
	m_textureID = new GLuint[numTextures];
	m_textureTarget = textureTarget;
	m_numTextures = numTextures;
	m_width = width;
	m_height = height;
	m_frameBuffer = 0;
	m_renderBuffer = 0;

	InitTextures(data, filters);
	InitRenderTargets(attachments);
}

TextureData::~TextureData()
{
	if(*m_textureID) glDeleteTextures(m_numTextures, m_textureID);
	if(m_frameBuffer) glDeleteFramebuffers(1, &m_frameBuffer);
	if(m_renderBuffer) glDeleteRenderbuffers(1, &m_renderBuffer);
	if(m_textureID) delete[] m_textureID;
}

void TextureData::InitTextures(unsigned char** data, GLfloat* filters)
{
	glGenTextures(m_numTextures, m_textureID);
	for(int i = 0; i < m_numTextures; i++)
	{
		glBindTexture(m_textureTarget, m_textureID[i]);

		glTexParameterf(m_textureTarget, GL_TEXTURE_MIN_FILTER, filters[i]);
		glTexParameterf(m_textureTarget, GL_TEXTURE_MAG_FILTER, filters[i]);

		glTexImage2D(m_textureTarget, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data[i]);
	}
}

void TextureData::InitRenderTargets(GLenum* attachments)
{
	if(attachments == 0)
		return;

	GLenum drawBuffers[32];      //32 is the max number of bound textures in OpenGL
	assert(m_numTextures <= 32); //Assert to be sure no buffer overrun should occur

	bool hasDepth = false;
	for(int i = 0; i < m_numTextures; i++)
	{
		if(attachments[i] == GL_DEPTH_ATTACHMENT)
		{
			drawBuffers[i] = GL_NONE;
			hasDepth = true;
		}
		else
			drawBuffers[i] = attachments[i];

		if(attachments[i] == GL_NONE)
			continue;

		if(m_frameBuffer == 0)
		{
			glGenFramebuffers(1, &m_frameBuffer);
			glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_frameBuffer);
		}

		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachments[i], m_textureTarget, m_textureID[i], 0);
	}

	if(m_frameBuffer == 0)
		return;

	if(!hasDepth)
	{
		glGenRenderbuffers(1, &m_renderBuffer);
		glBindRenderbuffer(GL_RENDERBUFFER, m_renderBuffer);
		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_width, m_height);
		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_renderBuffer);
	}

	glDrawBuffers(m_numTextures, drawBuffers);

	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
	{
		std::cerr << "Framebuffer creation failed!" << std::endl;
		assert(false);
	}
}

void TextureData::Bind(int textureNum)
{
	glBindTexture(m_textureTarget, m_textureID[textureNum]);
}

void TextureData::BindAsRenderTarget()
{
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_frameBuffer);
	glViewport(0, 0, m_width, m_height);
}

Texture::Texture(const std::string& fileName, GLenum textureTarget, GLfloat filter, GLenum attachment)
{
 	m_fileName = fileName;

	std::map<std::string, TextureData*>::const_iterator it = s_resourceMap.find(fileName);
	if(it != s_resourceMap.end())
	{
		m_textureData = it->second;
		m_textureData->AddReference();
	}
	else
	{
		int x, y, bytesPerPixel;
		unsigned char* data = stbi_load(("./res/textures/" + fileName).c_str(), &x, &y, &bytesPerPixel, 4);

		if(data == NULL)
		{
			std::cerr << "Unable to load texture: " << fileName << std::endl;
		}

		m_textureData = new TextureData(textureTarget, x, y, 1, &data, &filter, &attachment);
		stbi_image_free(data);

		s_resourceMap.insert(std::pair<std::string, TextureData*>(fileName, m_textureData));
	}
}

Texture::Texture(int width, int height, unsigned char* data, GLenum textureTarget, GLfloat filter, GLenum attachment)
{
	m_fileName = "";
	m_textureData = new TextureData(textureTarget, width, height, 1, &data, &filter, &attachment);
}

Texture::~Texture()
{
	if(m_textureData && m_textureData->RemoveReference())
	{
		if(m_fileName.length() > 0)
			s_resourceMap.erase(m_fileName);

		delete m_textureData;
	}
}

void Texture::Bind(unsigned int unit) const
{
	assert(unit >= 0 && unit <= 31);
	glActiveTexture(GL_TEXTURE0 + unit);
	m_textureData->Bind(0);
}

void Texture::BindAsRenderTarget()
{
	m_textureData->BindAsRenderTarget();
}
<|endoftext|>


<commit_before>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

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

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Get hostname for an IP.  Hostnames are checked with reverse name lookup and
  checked that they doesn't resemble an ip.
*/

#include "mysql_priv.h"
#include "hash_filo.h"
#include <m_ctype.h>
#ifdef	__cplusplus
extern "C" {					// Because of SCO 3.2V4.2
#endif
#if !defined( __WIN__) && !defined(OS2)
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#include <netdb.h>
#include <sys/utsname.h>
#endif // __WIN__
#ifdef	__cplusplus
}
#endif

class host_entry :public hash_filo_element
{
public:
  char	 ip[sizeof(((struct in_addr *) 0)->s_addr)];
  uint	 errors;
  char	 *hostname;
};

static hash_filo *hostname_cache;
static pthread_mutex_t LOCK_hostname;

void hostname_cache_refresh()
{
  hostname_cache->clear();
}

bool hostname_cache_init()
{
  host_entry tmp;
  uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
  if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
				     sizeof(struct in_addr),NULL,
				     (hash_free_key) free,
				     &my_charset_latin1)))
    return 1;
  hostname_cache->clear();
  (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  return 0;
}

void hostname_cache_free()
{
  if (hostname_cache)
  {
    (void) pthread_mutex_destroy(&LOCK_hostname);
    delete hostname_cache;
    hostname_cache= 0;
  }
}

static void add_hostname(struct in_addr *in,const char *name)
{
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    host_entry *entry;
    if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      uint length=name ? (uint) strlen(name) : 0;

      if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
      {
	char *new_name;
	memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
	if (length)
	  memcpy(new_name= (char *) (entry+1), name, length+1);
	else
	  new_name=0;
	entry->hostname=new_name;
	entry->errors=0;
	(void) hostname_cache->add(entry);
      }
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }
}

inline void add_wrong_ip(struct in_addr *in)
{
  add_hostname(in,NullS);
}

void inc_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors++;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

void reset_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors=0;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

/* Deal with systems that don't defined INADDR_LOOPBACK */
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001UL
#endif

my_string ip_to_hostname(struct in_addr *in, uint *errors)
{
  uint i;
  host_entry *entry;
  DBUG_ENTER("ip_to_hostname");
  *errors=0;

  /* We always treat the loopback address as "localhost". */
  if (in->s_addr == INADDR_LOOPBACK)
    return (char *)my_localhost;

  /* Check first if we have name in cache */
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      char *name;
      if (!entry->hostname)
	name=0;					// Don't allow connection
      else
	name=my_strdup(entry->hostname,MYF(0));
      *errors= entry->errors;
      VOID(pthread_mutex_unlock(&hostname_cache->lock));
      DBUG_RETURN(name);
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }

  struct hostent *hp, *check;
  char *name;
  LINT_INIT(check);
#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
  int tmp_errno;
  struct hostent tmp_hostent, tmp_hostent2;
#ifdef HAVE_purify
  bzero(buff,sizeof(buff));		// Bug in purify
#endif
  if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
			   AF_INET,
			   &tmp_hostent,buff,sizeof(buff),&tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
    return 0;
  }
  if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
				 &tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
    /*
      Don't cache responses when the DSN server is down, as otherwise
      transient DNS failure may leave any number of clients (those
      that attempted to connect during the outage) unable to connect
      indefinitely.
    */
    if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA)
      add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])
  {
    DBUG_PRINT("error",("Got an empty hostname"));
    add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// Don't allow empty hostnames
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// out of memory
  }
  my_gethostbyname_r_free();
#else
  VOID(pthread_mutex_lock(&LOCK_hostname));
  if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("gethostbyaddr returned %d",errno));

    if (errno == HOST_NOT_FOUND || errno == NO_DATA)
      goto add_wrong_ip_and_return;
    /* Failure, don't cache responce */
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])				// Don't allow empty hostnames
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("Got an empty hostname"));
    goto add_wrong_ip_and_return;
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_RETURN(0);				// out of memory
  }
  check=gethostbyname(name);
  VOID(pthread_mutex_unlock(&LOCK_hostname));
  if (!check)
  {
    DBUG_PRINT("error",("gethostbyname returned %d",errno));
    my_free(name,MYF(0));
    DBUG_RETURN(0);
  }
#endif

  /* Don't accept hostnames that starts with digits because they may be
     false ip:s */
  if (my_isdigit(&my_charset_latin1,name[0]))
  {
    char *pos;
    for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ;
    if (*pos == '.')
    {
      DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
      my_free(name,MYF(0));
      goto add_wrong_ip_and_return;
    }
  }

  /* Check that 'gethostbyname' returned the used ip */
  for (i=0; check->h_addr_list[i]; i++)
  {
    if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
    {
      add_hostname(in,name);
      DBUG_RETURN(name);
    }
  }
  DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
  my_free(name,MYF(0));

add_wrong_ip_and_return:
  add_wrong_ip(in);
  DBUG_RETURN(0);
}
<commit_msg>Fix shortcircuit of 127.0.0.1 -> localhost lookup on little-endian machines. (Bug #11822)<commit_after>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

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

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Get hostname for an IP.  Hostnames are checked with reverse name lookup and
  checked that they doesn't resemble an ip.
*/

#include "mysql_priv.h"
#include "hash_filo.h"
#include <m_ctype.h>
#ifdef	__cplusplus
extern "C" {					// Because of SCO 3.2V4.2
#endif
#if !defined( __WIN__) && !defined(OS2)
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#include <netdb.h>
#include <sys/utsname.h>
#endif // __WIN__
#ifdef	__cplusplus
}
#endif

class host_entry :public hash_filo_element
{
public:
  char	 ip[sizeof(((struct in_addr *) 0)->s_addr)];
  uint	 errors;
  char	 *hostname;
};

static hash_filo *hostname_cache;
static pthread_mutex_t LOCK_hostname;

void hostname_cache_refresh()
{
  hostname_cache->clear();
}

bool hostname_cache_init()
{
  host_entry tmp;
  uint offset= (uint) ((char*) (&tmp.ip) - (char*) &tmp);
  if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
				     sizeof(struct in_addr),NULL,
				     (hash_free_key) free,
				     &my_charset_latin1)))
    return 1;
  hostname_cache->clear();
  (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
  return 0;
}

void hostname_cache_free()
{
  if (hostname_cache)
  {
    (void) pthread_mutex_destroy(&LOCK_hostname);
    delete hostname_cache;
    hostname_cache= 0;
  }
}

static void add_hostname(struct in_addr *in,const char *name)
{
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    host_entry *entry;
    if (!(entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      uint length=name ? (uint) strlen(name) : 0;

      if ((entry=(host_entry*) malloc(sizeof(host_entry)+length+1)))
      {
	char *new_name;
	memcpy_fixed(&entry->ip, &in->s_addr, sizeof(in->s_addr));
	if (length)
	  memcpy(new_name= (char *) (entry+1), name, length+1);
	else
	  new_name=0;
	entry->hostname=new_name;
	entry->errors=0;
	(void) hostname_cache->add(entry);
      }
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }
}

inline void add_wrong_ip(struct in_addr *in)
{
  add_hostname(in,NullS);
}

void inc_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors++;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

void reset_host_errors(struct in_addr *in)
{
  VOID(pthread_mutex_lock(&hostname_cache->lock));
  host_entry *entry;
  if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    entry->errors=0;
  VOID(pthread_mutex_unlock(&hostname_cache->lock));
}

/* Deal with systems that don't defined INADDR_LOOPBACK */
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001UL
#endif

my_string ip_to_hostname(struct in_addr *in, uint *errors)
{
  uint i;
  host_entry *entry;
  DBUG_ENTER("ip_to_hostname");
  *errors=0;

  /* We always treat the loopback address as "localhost". */
  if (in->s_addr == htonl(INADDR_LOOPBACK))
    DBUG_RETURN((char *)my_localhost);

  /* Check first if we have name in cache */
  if (!(specialflag & SPECIAL_NO_HOST_CACHE))
  {
    VOID(pthread_mutex_lock(&hostname_cache->lock));
    if ((entry=(host_entry*) hostname_cache->search((gptr) &in->s_addr,0)))
    {
      char *name;
      if (!entry->hostname)
	name=0;					// Don't allow connection
      else
	name=my_strdup(entry->hostname,MYF(0));
      *errors= entry->errors;
      VOID(pthread_mutex_unlock(&hostname_cache->lock));
      DBUG_RETURN(name);
    }
    VOID(pthread_mutex_unlock(&hostname_cache->lock));
  }

  struct hostent *hp, *check;
  char *name;
  LINT_INIT(check);
#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
  char buff[GETHOSTBYADDR_BUFF_SIZE],buff2[GETHOSTBYNAME_BUFF_SIZE];
  int tmp_errno;
  struct hostent tmp_hostent, tmp_hostent2;
#ifdef HAVE_purify
  bzero(buff,sizeof(buff));		// Bug in purify
#endif
  if (!(hp=gethostbyaddr_r((char*) in,sizeof(*in),
			   AF_INET,
			   &tmp_hostent,buff,sizeof(buff),&tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyaddr_r returned %d",tmp_errno));
    return 0;
  }
  if (!(check=my_gethostbyname_r(hp->h_name,&tmp_hostent2,buff2,sizeof(buff2),
				 &tmp_errno)))
  {
    DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno));
    /*
      Don't cache responses when the DSN server is down, as otherwise
      transient DNS failure may leave any number of clients (those
      that attempted to connect during the outage) unable to connect
      indefinitely.
    */
    if (tmp_errno == HOST_NOT_FOUND || tmp_errno == NO_DATA)
      add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])
  {
    DBUG_PRINT("error",("Got an empty hostname"));
    add_wrong_ip(in);
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// Don't allow empty hostnames
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    my_gethostbyname_r_free();
    DBUG_RETURN(0);				// out of memory
  }
  my_gethostbyname_r_free();
#else
  VOID(pthread_mutex_lock(&LOCK_hostname));
  if (!(hp=gethostbyaddr((char*) in,sizeof(*in), AF_INET)))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("gethostbyaddr returned %d",errno));

    if (errno == HOST_NOT_FOUND || errno == NO_DATA)
      goto add_wrong_ip_and_return;
    /* Failure, don't cache responce */
    DBUG_RETURN(0);
  }
  if (!hp->h_name[0])				// Don't allow empty hostnames
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_PRINT("error",("Got an empty hostname"));
    goto add_wrong_ip_and_return;
  }
  if (!(name=my_strdup(hp->h_name,MYF(0))))
  {
    VOID(pthread_mutex_unlock(&LOCK_hostname));
    DBUG_RETURN(0);				// out of memory
  }
  check=gethostbyname(name);
  VOID(pthread_mutex_unlock(&LOCK_hostname));
  if (!check)
  {
    DBUG_PRINT("error",("gethostbyname returned %d",errno));
    my_free(name,MYF(0));
    DBUG_RETURN(0);
  }
#endif

  /* Don't accept hostnames that starts with digits because they may be
     false ip:s */
  if (my_isdigit(&my_charset_latin1,name[0]))
  {
    char *pos;
    for (pos= name+1 ; my_isdigit(&my_charset_latin1,*pos); pos++) ;
    if (*pos == '.')
    {
      DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
      my_free(name,MYF(0));
      goto add_wrong_ip_and_return;
    }
  }

  /* Check that 'gethostbyname' returned the used ip */
  for (i=0; check->h_addr_list[i]; i++)
  {
    if (*(uint32*)(check->h_addr_list)[i] == in->s_addr)
    {
      add_hostname(in,name);
      DBUG_RETURN(name);
    }
  }
  DBUG_PRINT("error",("Couldn't verify hostname with gethostbyname"));
  my_free(name,MYF(0));

add_wrong_ip_and_return:
  add_wrong_ip(in);
  DBUG_RETURN(0);
}
<|endoftext|>


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

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

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

=========================================================================*/
#include "otbCommandLineArgumentParser.h"
#include "otbMacro.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbGCPsToRPCSensorModelImageFilter.h"
#include "otbGenericRSTransform.h"
#include "otbGeoInformationConversion.h"
#include "otbGeographicalDistance.h"

int otbGCPsToRPCSensorModelImageFilterCheckRpcModel(int argc, char* argv[])
{
  // Set command line arguments
  typedef otb::CommandLineArgumentParser ParserType;
  ParserType::Pointer parser = ParserType::New();

  parser->AddInputImage();
  parser->AddOption("--DEMDirectory", "Path to the DEM directory ", "-dem", 1, false);
  parser->AddOptionNParams("--GroudControlPoints",
                           "Ground Control Points to estimate sensor model a1x a1y b1x b1y b1z ... aNx aNy aNz bNx bNy bNz",
                           "-gcp", true);
  parser->AddOption("--ErrorAllowed", "Error allowed to declare a point not good ", "-err", 1, false);

  // Parse the command line
  typedef otb::CommandLineArgumentParseResult ParserResultType;
  ParserResultType::Pointer  parseResult = ParserResultType::New();

  try
  {
    parser->ParseCommandLine(argc, argv, parseResult);
  }
  catch ( itk::ExceptionObject & err )
  {
    std::string descriptionException = err.GetDescription();
    if (descriptionException.find("ParseCommandLine(): Help Parser") != std::string::npos)
    {
    return EXIT_SUCCESS;
    }
    if (descriptionException.find("ParseCommandLine(): Version Parser") != std::string::npos)
      {
      return EXIT_SUCCESS;
      }
    return EXIT_FAILURE;
  }

  // Check if the number of gcp pairs point is consistent
  unsigned int nbPoints = parseResult->GetNumberOfParameters("--GroudControlPoints");

  if (nbPoints % 5 != 0)
    {
    std::cerr << "Inconsistent GCPs description!" << std::endl;
    return EXIT_FAILURE;
    }

  typedef otb::VectorImage<float, 2>                      ImageType;
  typedef otb::ImageFileReader<ImageType>                 ReaderType;
  typedef otb::GCPsToRPCSensorModelImageFilter<ImageType> GCPsToSensorModelFilterType;
  typedef GCPsToSensorModelFilterType::Point2DType        Point2DType;
  typedef GCPsToSensorModelFilterType::Point3DType        Point3DType;
  typedef otb::GenericRSTransform<double, 2, 2>           GenericRSTransformType;
  typedef otb::GeographicalDistance<ImageType::PointType>          GeoDistanceType;

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(parseResult->GetInputImage());
  reader->UpdateOutputInformation();

  GCPsToSensorModelFilterType::Pointer rpcEstimator = GCPsToSensorModelFilterType::New();
  rpcEstimator->SetInput(reader->GetOutput());

  unsigned int nbGCPs = nbPoints / 5;
  std::cout << "Receiving " << nbPoints << " from command line." << std::endl;

  for (unsigned int gcpId = 0; gcpId < nbGCPs; ++gcpId)
    {
    Point2DType sensorPoint;
    sensorPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints",     gcpId * 5);
    sensorPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 1 + gcpId * 5);

    Point3DType geoPoint;
    geoPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints", 2 + gcpId * 5);
    geoPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 3 + gcpId * 5);
    geoPoint[2] = parseResult->GetParameterFloat("--GroudControlPoints", 4 + gcpId * 5);

    std::cout << "Adding GCP sensor: " << sensorPoint << " <-> geo: " << geoPoint << std::endl;

    rpcEstimator->AddGCP(sensorPoint, geoPoint);
    }

  // Estimate the rpc model
  rpcEstimator->GetOutput()->UpdateOutputInformation();

  // Instancicate a GenericRSTransform in order to transform the
  // indexes, using the rpcModel estimated, into geographical
  // coordiantes.
  // The test will check for nan coordinates, and the distance between
  // geographical coordinates.

  GenericRSTransformType::Pointer grsTrasnform = GenericRSTransformType::New();
  grsTrasnform->SetInputKeywordList(rpcEstimator->GetKeywordlist());
  grsTrasnform->SetOutputProjectionRef(otb::GeoInformationConversion::ToWKT(4326));

  // Set the DEM Directory if any
  if(parseResult->IsOptionPresent("--DEMDirectory"))
    {
    grsTrasnform->SetDEMDirectory(parseResult->GetParameterString("--DEMDirectory"));
    }
  grsTrasnform->InstanciateTransform();

  // Test
  GeoDistanceType::Pointer geoDistance = GeoDistanceType::New();
  bool isErrorDetected = false;

  for (unsigned int gcpId = 0; gcpId < nbGCPs; ++gcpId)
    {
    ImageType::IndexType index;
    index[0] = parseResult->GetParameterFloat("--GroudControlPoints",     gcpId * 5);
    index[1] = parseResult->GetParameterFloat("--GroudControlPoints", 1 + gcpId * 5);

    ImageType::PointType point, transformedPoint;
    reader->GetOutput()->TransformIndexToPhysicalPoint(index, point);
    transformedPoint = grsTrasnform->TransformPoint(point);

    // reference point
    ImageType::PointType geoPoint;
    geoPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints", 2 + gcpId * 5);
    geoPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 3 + gcpId * 5);

    // Search for nans
    if ( vnl_math_isnan(transformedPoint[0]) || vnl_math_isnan(transformedPoint[1]) )
      {
      std::cout << "Reference : "<< geoPoint
                <<" --> Result of the reprojection using the estimated RpcModel "<<  transformedPoint
                << std::endl;
      std::cout<<"The result of the projection is nan, there is a problem with the estimated RpcModel "
               << std::endl<<std::endl;
      isErrorDetected = true;
      }

    // Search for wrong projection results
    double residual = geoDistance->Evaluate(geoPoint, transformedPoint);
    if( residual > parseResult->GetParameterFloat("--ErrorAllowed"))
      {
      std::cout << "Reference : "<< geoPoint
                <<" --> Result of the reprojection using the estimated RpcModel "
                << grsTrasnform->TransformPoint(point)
                << std::endl
                << " Residual ["<< residual << "] is higher than the tolerance ["
                << parseResult->GetParameterFloat("--ErrorAllowed")
                <<"], there is a problem with the estimated RpcModel"
                <<std::endl<<std::endl;
      isErrorDetected = true;
      }
    }

  // Is there an error
  if ( isErrorDetected )
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}
<commit_msg>ENH: add average elevation<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

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

=========================================================================*/
#include "otbCommandLineArgumentParser.h"
#include "otbMacro.h"
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbGCPsToRPCSensorModelImageFilter.h"
#include "otbGenericRSTransform.h"
#include "otbGeoInformationConversion.h"
#include "otbGeographicalDistance.h"

int otbGCPsToRPCSensorModelImageFilterCheckRpcModel(int argc, char* argv[])
{
  // Set command line arguments
  typedef otb::CommandLineArgumentParser ParserType;
  ParserType::Pointer parser = ParserType::New();

  parser->AddInputImage();
  parser->AddOption("--DEMDirectory", "Path to the DEM directory ", "-dem", 1, false);
  parser->AddOptionNParams("--GroudControlPoints",
                           "Ground Control Points to estimate sensor model a1x a1y b1x b1y b1z ... aNx aNy aNz bNx bNy bNz",
                           "-gcp", true);
  parser->AddOption("--ErrorAllowed", "Error allowed to declare a point not good ", "-err", 1, false);

  // Parse the command line
  typedef otb::CommandLineArgumentParseResult ParserResultType;
  ParserResultType::Pointer  parseResult = ParserResultType::New();

  try
  {
    parser->ParseCommandLine(argc, argv, parseResult);
  }
  catch ( itk::ExceptionObject & err )
  {
    std::string descriptionException = err.GetDescription();
    if (descriptionException.find("ParseCommandLine(): Help Parser") != std::string::npos)
    {
    return EXIT_SUCCESS;
    }
    if (descriptionException.find("ParseCommandLine(): Version Parser") != std::string::npos)
      {
      return EXIT_SUCCESS;
      }
    return EXIT_FAILURE;
  }

  // Check if the number of gcp pairs point is consistent
  unsigned int nbPoints = parseResult->GetNumberOfParameters("--GroudControlPoints");

  if (nbPoints % 5 != 0)
    {
    std::cerr << "Inconsistent GCPs description!" << std::endl;
    return EXIT_FAILURE;
    }

  typedef otb::VectorImage<float, 2>                      ImageType;
  typedef otb::ImageFileReader<ImageType>                 ReaderType;
  typedef otb::GCPsToRPCSensorModelImageFilter<ImageType> GCPsToSensorModelFilterType;
  typedef GCPsToSensorModelFilterType::Point2DType        Point2DType;
  typedef GCPsToSensorModelFilterType::Point3DType        Point3DType;
  typedef otb::GenericRSTransform<double, 2, 2>           GenericRSTransformType;
  typedef otb::GeographicalDistance<ImageType::PointType>          GeoDistanceType;

  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(parseResult->GetInputImage());
  reader->UpdateOutputInformation();

  GCPsToSensorModelFilterType::Pointer rpcEstimator = GCPsToSensorModelFilterType::New();
  rpcEstimator->SetInput(reader->GetOutput());

  unsigned int nbGCPs = nbPoints / 5;
  std::cout << "Receiving " << nbPoints << " from command line." << std::endl;

  for (unsigned int gcpId = 0; gcpId < nbGCPs; ++gcpId)
    {
    Point2DType sensorPoint;
    sensorPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints",     gcpId * 5);
    sensorPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 1 + gcpId * 5);

    Point3DType geoPoint;
    geoPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints", 2 + gcpId * 5);
    geoPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 3 + gcpId * 5);
    geoPoint[2] = parseResult->GetParameterFloat("--GroudControlPoints", 4 + gcpId * 5);

    std::cout << "Adding GCP sensor: " << sensorPoint << " <-> geo: " << geoPoint << std::endl;

    rpcEstimator->AddGCP(sensorPoint, geoPoint);
    }

  // Estimate the rpc model
  rpcEstimator->GetOutput()->UpdateOutputInformation();

  // Instancicate a GenericRSTransform in order to transform the
  // indexes, using the rpcModel estimated, into geographical
  // coordiantes.
  // The test will check for nan coordinates, and the distance between
  // geographical coordinates.

  GenericRSTransformType::Pointer grsTrasnform = GenericRSTransformType::New();
  grsTrasnform->SetInputKeywordList(rpcEstimator->GetKeywordlist());
  grsTrasnform->SetOutputProjectionRef(otb::GeoInformationConversion::ToWKT(4326));

  // Set the DEM Directory if any
  if(parseResult->IsOptionPresent("--DEMDirectory"))
    {
    grsTrasnform->SetDEMDirectory(parseResult->GetParameterString("--DEMDirectory"));
    }
  else
    {
      grsTrasnform->SetAverageElevation(0);
    }

  grsTrasnform->InstanciateTransform();

  // Test
  GeoDistanceType::Pointer geoDistance = GeoDistanceType::New();
  bool isErrorDetected = false;

  for (unsigned int gcpId = 0; gcpId < nbGCPs; ++gcpId)
    {
    ImageType::IndexType index;
    index[0] = parseResult->GetParameterFloat("--GroudControlPoints",     gcpId * 5);
    index[1] = parseResult->GetParameterFloat("--GroudControlPoints", 1 + gcpId * 5);

    ImageType::PointType point, transformedPoint;
    reader->GetOutput()->TransformIndexToPhysicalPoint(index, point);
    transformedPoint = grsTrasnform->TransformPoint(point);

    // reference point
    ImageType::PointType geoPoint;
    geoPoint[0] = parseResult->GetParameterFloat("--GroudControlPoints", 2 + gcpId * 5);
    geoPoint[1] = parseResult->GetParameterFloat("--GroudControlPoints", 3 + gcpId * 5);

    // Search for nans
    if ( vnl_math_isnan(transformedPoint[0]) || vnl_math_isnan(transformedPoint[1]) )
      {
      std::cout << "Reference : "<< geoPoint
                <<" --> Result of the reprojection using the estimated RpcModel "<<  transformedPoint
                << std::endl;
      std::cout<<"The result of the projection is nan, there is a problem with the estimated RpcModel "
               << std::endl<<std::endl;
      isErrorDetected = true;
      }

    // Search for wrong projection results
    double residual = geoDistance->Evaluate(geoPoint, transformedPoint);
    if( residual > parseResult->GetParameterFloat("--ErrorAllowed"))
      {
      std::cout << "Reference : "<< geoPoint
                <<" --> Result of the reprojection using the estimated RpcModel "
                << grsTrasnform->TransformPoint(point)
                << std::endl
                << " Residual ["<< residual << "] is higher than the tolerance ["
                << parseResult->GetParameterFloat("--ErrorAllowed")
                <<"], there is a problem with the estimated RpcModel"
                <<std::endl<<std::endl;
      isErrorDetected = true;
      }
    }

  // Is there an error
  if ( isErrorDetected )
    return EXIT_FAILURE;

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "ICUBridgeCollationCompareFunctor.hpp"
#include "ICUBridge.hpp"

#include <PlatformSupport/DOMStringHelper.hpp>

#include <unicode/coll.h>

const StylesheetExecutionContextDefault::DefaultCollationCompareFunctor		ICUBridgeCollationCompareFunctor::s_defaultFunctor;

ICUBridgeCollationCompareFunctor::ICUBridgeCollationCompareFunctor() :
	m_isValid(false),
	m_collator(0)
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	m_collator = Collator::createInstance(theStatus);

	if (theStatus == U_ZERO_ERROR || theStatus == U_USING_DEFAULT_ERROR)
	{
		m_isValid = true;
	}
}

ICUBridgeCollationCompareFunctor::~ICUBridgeCollationCompareFunctor()
{
	delete m_collator;
}

static UChar	dummy = 0;

int
ICUBridgeCollationCompareFunctor::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
	if (isValid() == false)
	{
		return s_defaultFunctor(theLHS, theRHS);
	}
	else
	{
		assert(m_collator != 0);

#if defined(XALAN_USE_XERCES_DOMSTRING)
		// $$$ ToDo: This code is necessary because DOMStrings can
		// have a null representation.
		const XalanDOMChar* const	lhs = theLHS == 0 ? &dummy : theLHS;
		const XalanDOMChar* const	rhs = theRHS == 0 ? &dummy : theRHS;

		return m_collator->compare(
					lhs,
					length(lhs),
					rhs,
					length(rhs));
#else
		return m_collator->compare(
					theLHS,
					length(theLHS),
					theRHS,
					length(theRHS));
#endif
	}
}
<commit_msg>Removed support for Xerces' DOMString.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "ICUBridgeCollationCompareFunctor.hpp"
#include "ICUBridge.hpp"

#include <PlatformSupport/DOMStringHelper.hpp>

#include <unicode/coll.h>

const StylesheetExecutionContextDefault::DefaultCollationCompareFunctor		ICUBridgeCollationCompareFunctor::s_defaultFunctor;

ICUBridgeCollationCompareFunctor::ICUBridgeCollationCompareFunctor() :
	m_isValid(false),
	m_collator(0)
{
	UErrorCode	theStatus = U_ZERO_ERROR;

	m_collator = Collator::createInstance(theStatus);

	if (theStatus == U_ZERO_ERROR || theStatus == U_USING_DEFAULT_ERROR)
	{
		m_isValid = true;
	}
}

ICUBridgeCollationCompareFunctor::~ICUBridgeCollationCompareFunctor()
{
	delete m_collator;
}

static UChar	dummy = 0;

int
ICUBridgeCollationCompareFunctor::operator()(
			const XalanDOMChar*		theLHS,
			const XalanDOMChar*		theRHS) const
{
	if (isValid() == false)
	{
		return s_defaultFunctor(theLHS, theRHS);
	}
	else
	{
		assert(m_collator != 0);

		return m_collator->compare(
					theLHS,
					length(theLHS),
					theRHS,
					length(theRHS));
	}
}
<|endoftext|>


<commit_before>/*
 * Servo.cpp
 *
 * Created: 07/05/2012 12:46:20 PM
 *  Author: teastman
 */

#include "Servo.h"

Servo::Servo(){
	m_minPulseWidth = 600;
	m_maxPulseWidth = 2400;
	m_maxVelocity = 500;
	m_limitVelocity = 100;
	m_pulseVelocity = pulseVelocity(100);
	m_currentPulse = 1500;
	m_destinationPulse = 1500;
	m_nextPulse = 1500;
	m_minPulse = 600;
	m_maxPulse = 2400;
	m_invert = false;
	m_normalize = false;
	m_applyVelocityLimit = false;
}

Servo::~Servo(){
	// Destroy things
}

void Servo::rotateTo(uint8_t angle){
	rotateTo(angle, m_limitVelocity);
}

void Servo::rotateTo(uint8_t angle, uint8_t velocity){
	angle = (angle>180) ? 180 : angle;
	m_destinationPulse = degreesToMicros(angle);
	m_destinationPulse = (m_destinationPulse>m_maxPulse) ? m_maxPulse : m_destinationPulse;
	m_destinationPulse = (m_destinationPulse<m_minPulse) ? m_minPulse : m_destinationPulse;
	m_pulseVelocity = pulseVelocity(velocity);
	m_applyVelocityLimit = true;
}

uint16_t Servo::calculateNextPulse(){
	m_currentPulse = m_nextPulse;
	if(m_applyVelocityLimit)
	{
		if(m_currentPulse == m_destinationPulse)
		{
			// Calculated first because it is the most common scenario.
			// do nothing;
		}
		else if(m_destinationPulse > m_currentPulse)
		{
			m_nextPulse = m_pulseVelocity + m_currentPulse;
			if(m_nextPulse > m_destinationPulse)
				m_nextPulse = m_destinationPulse;
		}
		else
		{
			m_nextPulse = m_currentPulse - m_pulseVelocity;
			if(m_nextPulse < m_destinationPulse)
				m_nextPulse = m_destinationPulse;
		}
	}
	else
	{
		m_nextPulse = m_destinationPulse;
	}
	return m_nextPulse;
}

uint8_t Servo::currentAngle() const{
	return microsToDegrees(m_currentPulse);
}

uint8_t Servo::destinationAngle() const{
	return microsToDegrees(m_destinationPulse);
}

uint8_t Servo::nextAngle() const{
	return microsToDegrees(m_nextPulse);
}

uint16_t Servo::currentPulse() const{
	return m_currentPulse;
}

uint16_t Servo::destinationPulse() const{
	return m_destinationPulse;
}

uint16_t Servo::nextPulse() const{
	return m_nextPulse;
}

uint16_t Servo::minPulseWidth(){
	return m_minPulseWidth;
}

void Servo::minPulseWidth(uint16_t pulse){
	m_minPulseWidth = pulse;
}

uint16_t Servo::maxPulseWidth(){
	return m_maxPulseWidth;
}

void Servo::maxPulseWidth(uint16_t pulse){
	m_maxPulseWidth = pulse;
}

uint16_t Servo::maxVelocity() const{
	return m_maxVelocity;
}

void Servo::maxVelocity(uint16_t maxVelocity){
	m_maxVelocity = maxVelocity;
}

uint8_t	 Servo::limitVelocity() const{
	return m_limitVelocity;
}

void Servo::limitVelocity(uint8_t velocity){
	velocity = (velocity>100) ? 100 : velocity;
	m_limitVelocity = velocity;
	m_pulseVelocity = pulseVelocity(velocity);
	m_applyVelocityLimit = true;
}

void Servo::unlimitVelocity(){
	m_applyVelocityLimit = false;
}

bool Servo::isLimited(){
	return m_applyVelocityLimit;
}

void Servo::limit(uint8_t minAngle, uint8_t maxAngle){
	m_minPulse = degreesToMicros(minAngle);
	m_maxPulse = degreesToMicros(maxAngle);
}

uint8_t Servo::minAngle() const{
	return microsToDegrees(m_minPulse);
}

void Servo::minAngle(uint8_t minAngle){
	m_minPulse = degreesToMicros(minAngle);
}

uint8_t Servo::maxAngle() const{
	return microsToDegrees(m_maxPulse);
}

void Servo::maxAngle(uint8_t maxAngle){
	m_maxPulse = degreesToMicros(maxAngle);
}

bool Servo::invert() const{
	return m_invert;
}

void Servo::invert(bool invert){
	m_invert = invert;
}

bool Servo::normalize() const{
	return m_normalize;
}

void Servo::normalize(bool normalize){
	m_normalize = normalize;
}

// the / 50 is to translate the max velocity from per second to per update.
// The updates are being sent out at a rate of 50 Hz or once every 20us
uint16_t Servo::pulseVelocity(uint8_t velocity) const{
	velocity = (velocity>100) ? 100 : velocity;
	return degreesToMicros((m_maxVelocity / 50) * ((double)velocity / 100.0));
}

uint16_t Servo::degreesToMicros(uint8_t val) const{
	return (m_maxPulseWidth - m_minPulseWidth) / 180 * val + m_minPulseWidth;
}

uint8_t Servo::microsToDegrees(uint16_t val) const{
	return (uint8_t)(180.0 / (double)(m_maxPulseWidth - m_minPulseWidth) * (val - m_minPulseWidth));
}<commit_msg>Fixed pulse velocity method<commit_after>/*
 * Servo.cpp
 *
 * Created: 07/05/2012 12:46:20 PM
 *  Author: teastman
 */

#include "Servo.h"

Servo::Servo(){
	m_minPulseWidth = 600;
	m_maxPulseWidth = 2400;
	m_maxVelocity = 500;
	m_limitVelocity = 100;
	m_pulseVelocity = pulseVelocity(100);
	m_currentPulse = 1500;
	m_destinationPulse = 1500;
	m_nextPulse = 1500;
	m_minPulse = 600;
	m_maxPulse = 2400;
	m_invert = false;
	m_normalize = false;
	m_applyVelocityLimit = false;
}

Servo::~Servo(){
	// Destroy things
}

void Servo::rotateTo(uint8_t angle){
	rotateTo(angle, m_limitVelocity);
}

void Servo::rotateTo(uint8_t angle, uint8_t velocity){
	angle = (angle>180) ? 180 : angle;
	m_destinationPulse = degreesToMicros(angle);
	m_destinationPulse = (m_destinationPulse>m_maxPulse) ? m_maxPulse : m_destinationPulse;
	m_destinationPulse = (m_destinationPulse<m_minPulse) ? m_minPulse : m_destinationPulse;
	m_pulseVelocity = pulseVelocity(velocity);
	m_applyVelocityLimit = true;
}

uint16_t Servo::calculateNextPulse(){
	m_currentPulse = m_nextPulse;
	if(m_applyVelocityLimit)
	{
		if(m_currentPulse == m_destinationPulse)
		{
			// Calculated first because it is the most common scenario.
			// do nothing;
		}
		else if(m_destinationPulse > m_currentPulse)
		{
			m_nextPulse = m_pulseVelocity + m_currentPulse;
			if(m_nextPulse > m_destinationPulse)
				m_nextPulse = m_destinationPulse;
		}
		else
		{
			m_nextPulse = m_currentPulse - m_pulseVelocity;
			if(m_nextPulse < m_destinationPulse)
				m_nextPulse = m_destinationPulse;
		}
	}
	else
	{
		m_nextPulse = m_destinationPulse;
	}
	return m_nextPulse;
}

uint8_t Servo::currentAngle() const{
	return microsToDegrees(m_currentPulse);
}

uint8_t Servo::destinationAngle() const{
	return microsToDegrees(m_destinationPulse);
}

uint8_t Servo::nextAngle() const{
	return microsToDegrees(m_nextPulse);
}

uint16_t Servo::currentPulse() const{
	return m_currentPulse;
}

uint16_t Servo::destinationPulse() const{
	return m_destinationPulse;
}

uint16_t Servo::nextPulse() const{
	return m_nextPulse;
}

uint16_t Servo::minPulseWidth(){
	return m_minPulseWidth;
}

void Servo::minPulseWidth(uint16_t pulse){
	m_minPulseWidth = pulse;
}

uint16_t Servo::maxPulseWidth(){
	return m_maxPulseWidth;
}

void Servo::maxPulseWidth(uint16_t pulse){
	m_maxPulseWidth = pulse;
}

uint16_t Servo::maxVelocity() const{
	return m_maxVelocity;
}

void Servo::maxVelocity(uint16_t maxVelocity){
	m_maxVelocity = maxVelocity;
}

uint8_t	 Servo::limitVelocity() const{
	return m_limitVelocity;
}

void Servo::limitVelocity(uint8_t velocity){
	velocity = (velocity>100) ? 100 : velocity;
	m_limitVelocity = velocity;
	m_pulseVelocity = pulseVelocity(velocity);
	m_applyVelocityLimit = true;
}

void Servo::unlimitVelocity(){
	m_applyVelocityLimit = false;
}

bool Servo::isLimited(){
	return m_applyVelocityLimit;
}

void Servo::limit(uint8_t minAngle, uint8_t maxAngle){
	m_minPulse = degreesToMicros(minAngle);
	m_maxPulse = degreesToMicros(maxAngle);
}

uint8_t Servo::minAngle() const{
	return microsToDegrees(m_minPulse);
}

void Servo::minAngle(uint8_t minAngle){
	m_minPulse = degreesToMicros(minAngle);
}

uint8_t Servo::maxAngle() const{
	return microsToDegrees(m_maxPulse);
}

void Servo::maxAngle(uint8_t maxAngle){
	m_maxPulse = degreesToMicros(maxAngle);
}

bool Servo::invert() const{
	return m_invert;
}

void Servo::invert(bool invert){
	m_invert = invert;
}

bool Servo::normalize() const{
	return m_normalize;
}

void Servo::normalize(bool normalize){
	m_normalize = normalize;
}

// the / 50 is to translate the max velocity from per second to per update.
// The updates are being sent out at a rate of 50 Hz or once every 20us
uint16_t Servo::pulseVelocity(uint8_t velocity) const{
	velocity = (velocity>100) ? 100 : velocity;
	return (uint16_t)(((double)m_maxVelocity / 50.0) * ((double)velocity / 100.0) * ((double)(m_maxPulseWidth - m_minPulseWidth) / 180.0));
}

// Converts a give angle to the appropriate microsecond burst.
uint16_t Servo::degreesToMicros(uint8_t val) const{
	return (m_maxPulseWidth - m_minPulseWidth) / 180 * val + m_minPulseWidth;
}

// Converts a microsecond burst into an angle.
uint8_t Servo::microsToDegrees(uint16_t val) const{
	return (uint8_t)(180.0 / (double)(m_maxPulseWidth - m_minPulseWidth) * (val - m_minPulseWidth));
}<|endoftext|>


<commit_before>
/******************************************************************************
 *
 *  file:  CmdLine.cpp
 *
 *  Copyright (c) 2003, Michael E. Smoot .
 *  All rights reverved.
 *
 *  See the file COPYING in the top directory of this distribution for
 *  more information.
 *
 *  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 <tclap/CommandLine.h>

using namespace std;

namespace TCLAP {

CmdLine::CmdLine(const string& n, const string& m, const string& v )
: _progName(n),
  _message(m),
  _version(v),
  _numRequired(0),
  _delimiter(' ')
{
	_constructor();
}

CmdLine::CmdLine(const string& m, char delim, const string& v )
: _progName("not_set_yet"),
  _message(m),
  _version(v),
  _numRequired(0),
  _delimiter(delim)
{
	_constructor();
}

void CmdLine::_constructor()
{
	Arg::setDelimiter( _delimiter );

	SwitchArg* help = new SwitchArg("h","help",
					                "Displays usage information and exits.",
									false, new HelpVisitor( this ) );
	add( *help );

	SwitchArg* vers = new SwitchArg("v","version",
					                "Displays version information and exits.",
									false, new VersionVisitor( this ) );
	add( *vers );

	SwitchArg* ignore  = new SwitchArg(Arg::flagStartString,
				Arg::ignoreNameString,
               "Ignores the rest of the labeled arguments following this flag.",
			   false, new IgnoreRestVisitor() );
	add( *ignore );

}

void CmdLine::xorAdd( vector<Arg*>& ors )
{
	_xorHandler.add( ors );

	for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
	{
		(*it)->forceRequired();
		(*it)->setRequireLabel( "OR required" );

		add( *it );
	}
}

void CmdLine::xorAdd( Arg& a, Arg& b )
{
    vector<Arg*> ors;
    ors.push_back( &a );
    ors.push_back( &b );
	xorAdd( ors );
}

void CmdLine::add( Arg& a )
{
	add( &a );
}

void CmdLine::add( Arg* a )
{
	if ( find(_argList.begin(),_argList.end(), a) != _argList.end() )
	{
		cerr << "ADD ERROR:  Argument with same flag/name already exists: "
			 << a->toString() << "  Ignoring!" << endl;
		return;
	}

	a->addToList( _argList );

	if ( a->isRequired() ) _numRequired++;

}

void CmdLine::version(int exitVal)
{
	cout << endl << _progName << "  version: " << _version << endl << endl;
	exit( exitVal );
}

void CmdLine::_shortUsage( ostream& os )
{
	string s = _progName + " " + _xorHandler.shortUsage();

	for (ArgIterator it = _argList.begin(); it != _argList.end(); it++)
		if ( !_xorHandler.contains( (*it) ) )
			s += " " + (*it)->shortID();

	spacePrint( os, s, 75, 3, _progName.length() + 2 );
}

void CmdLine::_longUsage( ostream& os )
{
	_xorHandler.printLongUsage( os );

	for (ArgIterator it = _argList.begin(); it != _argList.end(); it++)
		if ( !_xorHandler.contains( (*it) ) )
		{
			spacePrint( os, (*it)->longID(), 75, 3, 3 );
			spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
			os << endl;
		}

	os << endl;
	spacePrint( os, _message, 75, 3, 0 );
}

void CmdLine::usage( int exitVal )
{
	cout << endl << "USAGE: " << endl << endl;

	_shortUsage( cout );

	cout << endl << endl << "Where: " << endl << endl;

	_longUsage( cout );

	cout << endl;

	exit( exitVal );
}

void CmdLine::parse(int argc, char** argv)
{
	try {

	_progName = argv[0];

	// this step is necessary so that we have easy access to mutable strings.
	vector<string> args;
  	for (int i = 1; i < argc; i++)
		args.push_back(argv[i]);

	int requiredCount = 0;

  	for (int i = 0; (unsigned int)i < args.size(); i++)
	{
		bool matched = false;
		for (ArgIterator it = _argList.begin(); it != _argList.end(); it++)
        {
			if ( (*it)->processArg( &i, args ) )
			{
				requiredCount += _xorHandler.check( *it );
				matched = true;
				break;
			}
        }

		// checks to see if the argument is an empty combined switch ...
		// and if so, then we've actually matched it
		if ( !matched && _emptyCombined( args[i] ) )
			matched = true;

		if ( !matched && !Arg::ignoreRest() )
			throw( ArgException("Couldn't find match for argument",args[i]));
    }

	if ( requiredCount < _numRequired )
		throw( ArgException("One or more required arguments missing!") );

	if ( requiredCount > _numRequired )
		throw( ArgException("Too many arguments!") );

	} catch ( ArgException e )
	{
		cerr << "PARSE ERROR: " << e.argId() << endl
			 << "             " << e.error() << endl << endl;

		cerr << "Brief USAGE: " << endl;

		_shortUsage( cerr );

		cerr << endl << "For complete USAGE and HELP type: "
			 << endl << "   " << _progName << " --help" << endl << endl;

		exit(1);
	}
}

bool CmdLine::_emptyCombined(const string& s)
{
	if ( s[0] != Arg::flagStartChar )
		return false;

	for ( int i = 1; (unsigned int)i < s.length(); i++ )
		if ( s[i] != Arg::blankChar )
			return false;

	return true;
}

}
<commit_msg>now throws exception on matching names/flags/desc<commit_after>
/******************************************************************************
 *
 *  file:  CmdLine.cpp
 *
 *  Copyright (c) 2003, Michael E. Smoot .
 *  All rights reverved.
 *
 *  See the file COPYING in the top directory of this distribution for
 *  more information.
 *
 *  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 <tclap/CommandLine.h>

using namespace std;

namespace TCLAP {

CmdLine::CmdLine(const string& n, const string& m, const string& v )
: _progName(n),
  _message(m),
  _version(v),
  _numRequired(0),
  _delimiter(' ')
{
	_constructor();
}

CmdLine::CmdLine(const string& m, char delim, const string& v )
: _progName("not_set_yet"),
  _message(m),
  _version(v),
  _numRequired(0),
  _delimiter(delim)
{
	_constructor();
}

void CmdLine::_constructor()
{
	Arg::setDelimiter( _delimiter );

	SwitchArg* help = new SwitchArg("h","help",
					                "Displays usage information and exits.",
									false, new HelpVisitor( this ) );
	add( *help );

	SwitchArg* vers = new SwitchArg("v","version",
					                "Displays version information and exits.",
									false, new VersionVisitor( this ) );
	add( *vers );

	SwitchArg* ignore  = new SwitchArg(Arg::flagStartString,
				Arg::ignoreNameString,
               "Ignores the rest of the labeled arguments following this flag.",
			   false, new IgnoreRestVisitor() );
	add( *ignore );

}

void CmdLine::xorAdd( vector<Arg*>& ors )
{
	_xorHandler.add( ors );

	for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
	{
		(*it)->forceRequired();
		(*it)->setRequireLabel( "OR required" );

		add( *it );
	}
}

void CmdLine::xorAdd( Arg& a, Arg& b )
{
    vector<Arg*> ors;
    ors.push_back( &a );
    ors.push_back( &b );
	xorAdd( ors );
}

void CmdLine::add( Arg& a )
{
	add( &a );
}

void CmdLine::add( Arg* a )
{
	for( ArgIterator iter = _argList.begin(); iter != _argList.end(); iter++ )
		if ( *a == *(*iter) )
			throw( ArgException( "Argument with same flag/name already exists!",
			                     a->longID() ) );

	a->addToList( _argList );

	if ( a->isRequired() ) _numRequired++;
}

void CmdLine::version(int exitVal)
{
	cout << endl << _progName << "  version: " << _version << endl << endl;
	exit( exitVal );
}

void CmdLine::_shortUsage( ostream& os )
{
	string s = _progName + " " + _xorHandler.shortUsage();

	for (ArgIterator it = _argList.begin(); it != _argList.end(); it++)
		if ( !_xorHandler.contains( (*it) ) )
			s += " " + (*it)->shortID();

	spacePrint( os, s, 75, 3, _progName.length() + 2 );
}

void CmdLine::_longUsage( ostream& os )
{
	_xorHandler.printLongUsage( os );

	for (ArgIterator it = _argList.begin(); it != _argList.end(); it++)
		if ( !_xorHandler.contains( (*it) ) )
		{
			spacePrint( os, (*it)->longID(), 75, 3, 3 );
			spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
			os << endl;
		}

	os << endl;
	spacePrint( os, _message, 75, 3, 0 );
}

void CmdLine::usage( int exitVal )
{
	cout << endl << "USAGE: " << endl << endl;

	_shortUsage( cout );

	cout << endl << endl << "Where: " << endl << endl;

	_longUsage( cout );

	cout << endl;

	exit( exitVal );
}

void CmdLine::parse(int argc, char** argv)
{
	try {

	_progName = argv[0];

	// this step is necessary so that we have easy access to mutable strings.
	vector<string> args;
  	for (int i = 1; i < argc; i++)
		args.push_back(argv[i]);

	int requiredCount = 0;

  	for (int i = 0; (unsigned int)i < args.size(); i++)
	{
		bool matched = false;
		for (ArgIterator it = _argList.begin(); it != _argList.end(); it++)
        {
			if ( (*it)->processArg( &i, args ) )
			{
				requiredCount += _xorHandler.check( *it );
				matched = true;
				break;
			}
        }

		// checks to see if the argument is an empty combined switch ...
		// and if so, then we've actually matched it
		if ( !matched && _emptyCombined( args[i] ) )
			matched = true;

		if ( !matched && !Arg::ignoreRest() )
			throw( ArgException("Couldn't find match for argument",args[i]));
    }

	if ( requiredCount < _numRequired )
		throw( ArgException("One or more required arguments missing!") );

	if ( requiredCount > _numRequired )
		throw( ArgException("Too many arguments!") );

	} catch ( ArgException e )
	{
		cerr << "PARSE ERROR: " << e.argId() << endl
			 << "             " << e.error() << endl << endl;

		cerr << "Brief USAGE: " << endl;

		_shortUsage( cerr );

		cerr << endl << "For complete USAGE and HELP type: "
			 << endl << "   " << _progName << " --help" << endl << endl;

		exit(1);
	}
}

bool CmdLine::_emptyCombined(const string& s)
{
	if ( s[0] != Arg::flagStartChar )
		return false;

	for ( int i = 1; (unsigned int)i < s.length(); i++ )
		if ( s[i] != Arg::blankChar )
			return false;

	return true;
}

}
<|endoftext|>


<commit_before>#include <Context.h>

#include <cmath>
#include <iostream>

using namespace std;
using namespace canvas;

void
Context::resize(unsigned int _width, unsigned int _height) {
  getDefaultSurface().resize(_width, _height, (unsigned int)(_width * getDisplayScale()), (unsigned int)(_height * getDisplayScale()), getDefaultSurface().getFormat());
  hit_regions.clear();
}

Context &
Context::fillRect(double x, double y, double w, double h) {
  beginPath().rect(x, y, w, h);
  return fill();
}

Context &
Context::strokeRect(double x, double y, double w, double h) {
  beginPath().rect(x, y, w, h);
  return stroke();
}

Context &
Context::clearRect(double x, double y, double w, double h) {
  Path path;
  path.rect(x, y, w, h);
  Style style(this);
  style = Color(0.0f, 0.0f, 0.0f, 0.0f);
  return renderPath(FILL, path, style, COPY);
}

Context &
Context::renderText(RenderMode mode, const Style & style, const std::string & text, double x, double y, Operator op) {
  if (hasNativeShadows()) {
    getDefaultSurface().renderText(mode, font, style, textBaseline.getValue(), textAlign.getValue(), text, x, y, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath);
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      int bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);

      Style shadow_style(this);
      shadow_style = shadowColor.getValue();
      shadow_style.color.alpha = 1.0f;
      shadow->renderText(mode, font, shadow_style, textBaseline.getValue(), textAlign.getValue(), text, x + shadowOffsetX.getValue() + bi, y + shadowOffsetY.getValue() + bi, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath);
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().renderText(mode, font, style, textBaseline.getValue(), textAlign.getValue(), text, x, y, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath);
  }
  return *this;
}

Context &
Context::renderPath(RenderMode mode, const Path & path, const Style & style, Operator op) {
  if (hasNativeShadows()) {
    getDefaultSurface().renderPath(mode, path, style, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath);
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      float bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);
      Style shadow_style(this);
      shadow_style = shadowColor.getValue();
      Path tmp_path = path, tmp_clipPath = clipPath;
      tmp_path.offset(shadowOffsetX.getValue() + bi, shadowOffsetY.getValue() + bi);
      tmp_clipPath.offset(shadowOffsetX.getValue() + bi, shadowOffsetY.getValue() + bi);

      shadow->renderPath(mode, tmp_path, shadow_style, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0, 0, 0, shadowColor.getValue(), tmp_clipPath);
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().renderPath(mode, path, style, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0, 0, 0, shadowColor.getValue(), clipPath);
  }
  return *this;
}

Context &
Context::drawImage(Surface & img, double x, double y, double w, double h) {
  if (hasNativeShadows()) {
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath, imageSmoothingEnabled);
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      float bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);

      shadow->drawImage(img, (x + bi + shadowOffsetX.getValue()) * getDisplayScale(), (y + bi + shadowOffsetY.getValue()) * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled);
      // shadow->colorFill(shadowColor.getValue());
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled);
  }
  return *this;
}

Context &
Context::drawImage(const Image & img, double x, double y, double w, double h) {
  if (hasNativeShadows()) {
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath, imageSmoothingEnabled);
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      float bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);

      shadow->drawImage(img, (x + bi + shadowOffsetX.getValue()) * getDisplayScale(), (y + bi + shadowOffsetY.getValue()) * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled);
      // shadow->colorFill(shadowColor.getValue());
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled);
  }
  return *this;
}

Context &
Context::save() {
  restore_stack.push_back(*this);
  return *this;
}

Context &
Context::restore() {
  if (!restore_stack.empty()) {
    *this = restore_stack.back();
    restore_stack.pop_back();
  }
  return *this;
}
<commit_msg>fix imageSmoothingEnabled usage<commit_after>#include <Context.h>

#include <cmath>
#include <iostream>

using namespace std;
using namespace canvas;

void
Context::resize(unsigned int _width, unsigned int _height) {
  getDefaultSurface().resize(_width, _height, (unsigned int)(_width * getDisplayScale()), (unsigned int)(_height * getDisplayScale()), getDefaultSurface().getFormat());
  hit_regions.clear();
}

Context &
Context::fillRect(double x, double y, double w, double h) {
  beginPath().rect(x, y, w, h);
  return fill();
}

Context &
Context::strokeRect(double x, double y, double w, double h) {
  beginPath().rect(x, y, w, h);
  return stroke();
}

Context &
Context::clearRect(double x, double y, double w, double h) {
  Path path;
  path.rect(x, y, w, h);
  Style style(this);
  style = Color(0.0f, 0.0f, 0.0f, 0.0f);
  return renderPath(FILL, path, style, COPY);
}

Context &
Context::renderText(RenderMode mode, const Style & style, const std::string & text, double x, double y, Operator op) {
  if (hasNativeShadows()) {
    getDefaultSurface().renderText(mode, font, style, textBaseline.getValue(), textAlign.getValue(), text, x, y, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath);
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      int bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);

      Style shadow_style(this);
      shadow_style = shadowColor.getValue();
      shadow_style.color.alpha = 1.0f;
      shadow->renderText(mode, font, shadow_style, textBaseline.getValue(), textAlign.getValue(), text, x + shadowOffsetX.getValue() + bi, y + shadowOffsetY.getValue() + bi, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath);
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().renderText(mode, font, style, textBaseline.getValue(), textAlign.getValue(), text, x, y, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath);
  }
  return *this;
}

Context &
Context::renderPath(RenderMode mode, const Path & path, const Style & style, Operator op) {
  if (hasNativeShadows()) {
    getDefaultSurface().renderPath(mode, path, style, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath);
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      float bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);
      Style shadow_style(this);
      shadow_style = shadowColor.getValue();
      Path tmp_path = path, tmp_clipPath = clipPath;
      tmp_path.offset(shadowOffsetX.getValue() + bi, shadowOffsetY.getValue() + bi);
      tmp_clipPath.offset(shadowOffsetX.getValue() + bi, shadowOffsetY.getValue() + bi);

      shadow->renderPath(mode, tmp_path, shadow_style, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0, 0, 0, shadowColor.getValue(), tmp_clipPath);
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().renderPath(mode, path, style, lineWidth.getValue(), op, getDisplayScale(), globalAlpha.getValue(), 0, 0, 0, shadowColor.getValue(), clipPath);
  }
  return *this;
}

Context &
Context::drawImage(Surface & img, double x, double y, double w, double h) {
  if (hasNativeShadows()) {
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath, imageSmoothingEnabled.getValue());
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      float bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);

      shadow->drawImage(img, (x + bi + shadowOffsetX.getValue()) * getDisplayScale(), (y + bi + shadowOffsetY.getValue()) * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled.getValue());
      // shadow->colorFill(shadowColor.getValue());
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled.getValue());
  }
  return *this;
}

Context &
Context::drawImage(const Image & img, double x, double y, double w, double h) {
  if (hasNativeShadows()) {
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), shadowBlur.getValue(), shadowOffsetX.getValue(), shadowOffsetY.getValue(), shadowColor.getValue(), clipPath, imageSmoothingEnabled.getValue());
  } else {
    if (hasShadow()) {
      float b = shadowBlur.getValue(), bs = shadowBlur.getValue() * getDisplayScale();
      float bi = int(ceil(b));
      auto shadow = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, R8);
      auto shadow2 = createSurface(getDefaultSurface().getLogicalWidth() + 2 * bi, getDefaultSurface().getLogicalHeight() + 2 * bi, RGBA8);

      shadow->drawImage(img, (x + bi + shadowOffsetX.getValue()) * getDisplayScale(), (y + bi + shadowOffsetY.getValue()) * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled.getValue());
      // shadow->colorFill(shadowColor.getValue());
#if 1
      shadow->slowBlur(bs, bs);
#else
      shadow->blur(bs);
#endif
      shadow->colorize(shadowColor.getValue(), *shadow2);
      getDefaultSurface().drawImage(*shadow2, -bi, -bi, shadow2->getActualWidth(), shadow2->getActualHeight(), getDisplayScale(), 1.0f, 0.0f, 0.0f, 0.0f, shadowColor.getValue(), Path(), false);
    }
    getDefaultSurface().drawImage(img, x * getDisplayScale(), y * getDisplayScale(), w * getDisplayScale(), h * getDisplayScale(), getDisplayScale(), globalAlpha.getValue(), 0.0f, 0.0f, 0.0f, shadowColor.getValue(), clipPath, imageSmoothingEnabled.getValue());
  }
  return *this;
}

Context &
Context::save() {
  restore_stack.push_back(*this);
  return *this;
}

Context &
Context::restore() {
  if (!restore_stack.empty()) {
    *this = restore_stack.back();
    restore_stack.pop_back();
  }
  return *this;
}
<|endoftext|>