<commit_before>
#pragma once

#include <cppexpose/typed/TypedEnum.hh>

#include <cassert>
#include <type_traits>

namespace cppexpose
{

template <typename T, typename BASE>
TypedEnum<T, BASE>::TypedEnum()
{
    // Create default enum strings
    this->setStrings(EnumDefaultStrings<T>()());
}

template <typename T, typename BASE>
TypedEnum<T, BASE>::~TypedEnum()
{
}

template <typename T, typename BASE>
std::vector<std::string> TypedEnum<T, BASE>::strings() const
{
    std::vector<std::string> strings;

    for (auto element : m_stringMap) {
        strings.push_back(element.second);
    }

    return strings;
}

template <typename T, typename BASE>
void TypedEnum<T, BASE>::setStrings(const std::map<T, std::string> & pairs)
{
    // Save map of enum value -> string representation
    m_stringMap = pairs;

    // Construct reverse map (string -> enum value)
    m_enumMap.clear();
    for (const std::pair<T, std::string> & pair : pairs)
    {
        assert(m_enumMap.count(pair.second) == 0);
        m_enumMap.insert(std::make_pair(pair.second, pair.first));
    }
}

template <typename T, typename BASE>
std::string TypedEnum<T, BASE>::typeName() const
{
    return "enum";
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::isNumber() const
{
    return true;
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::isIntegral() const
{
    return true;
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromVariant(const Variant & variant)
{
    if (variant.hasType<T>()) {
        this->setValue(variant.value<T>());
    } else {
        this->setValue((T)variant.value<int>());
    }
    return true;
}

template <typename T, typename BASE>
std::string TypedEnum<T, BASE>::toString() const
{
    // Check if value has a string representation
    const auto it = m_stringMap.find(this->value());

    // Return string representation
    if (it != m_stringMap.cend()) {
        return it->second;
    }

    return "";
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromString(const std::string & value)
{
    // Find enum of string representation
    auto it = m_enumMap.find(value);

    // Abort if it is not available
    if (it == m_enumMap.end()) {
        return false;
    }

    // Set value
    this->setValue((*it).second);
    return true;
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::toBool() const
{
    return (bool)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromBool(bool value)
{
    this->setValue((T)value);
    return true;
}

template <typename T, typename BASE>
long long TypedEnum<T, BASE>::toLongLong() const
{
    return (long long)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromLongLong(long long value)
{
    this->setValue((T)value);
    return true;
}

template <typename T, typename BASE>
unsigned long long TypedEnum<T, BASE>::toULongLong() const
{
    return (unsigned long long)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromULongLong(unsigned long long value)
{
    this->setValue((T)value);
    return true;
}

template <typename T, typename BASE>
double TypedEnum<T, BASE>::toDouble() const
{
    return (double)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromDouble(double value)
{
    this->setValue((T)static_cast<typename std::underlying_type<T>::type>(value));
    return true;
}

template <typename T>
std::map<T, std::string> EnumDefaultStrings<T>::operator()()
{
    return std::map<T, std::string>();
}

} // namespace cppexpose
<commit_msg>Add empty line<commit_after>
#pragma once

#include <cppexpose/typed/TypedEnum.hh>

#include <cassert>
#include <type_traits>

namespace cppexpose
{

template <typename T, typename BASE>
TypedEnum<T, BASE>::TypedEnum()
{
    // Create default enum strings
    this->setStrings(EnumDefaultStrings<T>()());
}

template <typename T, typename BASE>
TypedEnum<T, BASE>::~TypedEnum()
{
}

template <typename T, typename BASE>
std::vector<std::string> TypedEnum<T, BASE>::strings() const
{
    std::vector<std::string> strings;

    for (auto element : m_stringMap) {
        strings.push_back(element.second);
    }

    return strings;
}

template <typename T, typename BASE>
void TypedEnum<T, BASE>::setStrings(const std::map<T, std::string> & pairs)
{
    // Save map of enum value -> string representation
    m_stringMap = pairs;

    // Construct reverse map (string -> enum value)
    m_enumMap.clear();
    for (const std::pair<T, std::string> & pair : pairs)
    {
        assert(m_enumMap.count(pair.second) == 0);
        m_enumMap.insert(std::make_pair(pair.second, pair.first));
    }
}

template <typename T, typename BASE>
std::string TypedEnum<T, BASE>::typeName() const
{
    return "enum";
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::isNumber() const
{
    return true;
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::isIntegral() const
{
    return true;
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromVariant(const Variant & variant)
{
    if (variant.hasType<T>()) {
        this->setValue(variant.value<T>());
    } else {
        this->setValue((T)variant.value<int>());
    }

    return true;
}

template <typename T, typename BASE>
std::string TypedEnum<T, BASE>::toString() const
{
    // Check if value has a string representation
    const auto it = m_stringMap.find(this->value());

    // Return string representation
    if (it != m_stringMap.cend()) {
        return it->second;
    }

    return "";
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromString(const std::string & value)
{
    // Find enum of string representation
    auto it = m_enumMap.find(value);

    // Abort if it is not available
    if (it == m_enumMap.end()) {
        return false;
    }

    // Set value
    this->setValue((*it).second);
    return true;
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::toBool() const
{
    return (bool)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromBool(bool value)
{
    this->setValue((T)value);
    return true;
}

template <typename T, typename BASE>
long long TypedEnum<T, BASE>::toLongLong() const
{
    return (long long)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromLongLong(long long value)
{
    this->setValue((T)value);
    return true;
}

template <typename T, typename BASE>
unsigned long long TypedEnum<T, BASE>::toULongLong() const
{
    return (unsigned long long)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromULongLong(unsigned long long value)
{
    this->setValue((T)value);
    return true;
}

template <typename T, typename BASE>
double TypedEnum<T, BASE>::toDouble() const
{
    return (double)this->value();
}

template <typename T, typename BASE>
bool TypedEnum<T, BASE>::fromDouble(double value)
{
    this->setValue((T)static_cast<typename std::underlying_type<T>::type>(value));
    return true;
}

template <typename T>
std::map<T, std::string> EnumDefaultStrings<T>::operator()()
{
    return std::map<T, std::string>();
}

} // namespace cppexpose
<|endoftext|>


<commit_before>#include "./JPetSinogram.h"
#include <boost/numeric/ublas/matrix.hpp>
#include <vector>
#include <utility>
#include <cmath> //for sin and cos
using namespace boost::numeric::ublas;

JPetSinogram::JPetSinogram() { }

JPetSinogram::~JPetSinogram() { }

long long JPetSinogram::forwardProjection(float s, float theta, matrix<int> emissionMatrix) {
  long long sum = 0;

  if(s == 0)
    return sum; // not implemented yet

  if(theta == 90) {
    for(unsigned int i = 0; i < emissionMatrix.size1(); i++) {
      sum += emissionMatrix(i, s);
    }
  } else {
    //prosta prostopadła Ax + By + C = 0
    //w zmiennych biegunowych: x * cos(theta) + y * sin(theta) - s = 0
    //prostopadła x * (-sin(theta)) + y * cos(theta) + C = 0
    int x = std::floor(std::cos(-theta) * s);
    int y = -std::floor(std::sin(-theta) * s);
    float theta2 = 90 / emissionMatrix.size1();
    std::cout << "x: " << x << " y: " << y << " theta2: " << theta2 << std::endl;
    while(x >= 0 && y >= 0 && x < emissionMatrix.size1() && y < emissionMatrix.size2()) {
      sum += emissionMatrix(x, y);
      s++;
      x = std::floor(std::cos(-theta) * s);
      y = -std::round(std::sin(-theta) * s);
      std::cout << "x: " << x << " y: " << y << std::endl;
      //float cos = std::cos(theta2 - theta);
      //float r = s / cos;
//
      //x = std::round(std::cos(theta2) * r);
      //y = std::round(std::sin(theta2) * r);
      //std::cout << "x: " << x << " y: " << y << " theta2: " << theta2  << " r: " << r \
      //<< " cos " << cos << std::endl;
      //theta2 += 90 / emissionMatrix.size1();
    }
  }

  /*if(theta == 0) {
    for(unsigned int i = 0; i < emissionMatrix.size2(); i++) {
      sum += emissionMatrix(s, i);
    }
  } else if(theta == 90) {
    for(unsigned int i = 0; i < emissionMatrix.size1(); i++) {
      sum += emissionMatrix(i, s);
    }
  } else if(theta == 45) {
    unsigned int j = (emissionMatrix.size2() - 1) - s < 0 ? 0 : (emissionMatrix.size2() - 1) - s;
    unsigned int i = (emissionMatrix.size2() - 1) - s < 0 ? - ((emissionMatrix.size2() - 1 - s)) : 0;// select row, start from upper right corner
    for(; j < emissionMatrix.size2(); j++) { //-1 bcs matrix start from 0
      if(i < emissionMatrix.size1()) {
        sum += emissionMatrix(i, j);
        i++;
      }
      else { } // exception
    }

  }*/
  std::cout << "s: " << s << " theta: " << theta << " sum: " << sum << std::endl;
  return sum;
}

// std::vector<std::tuple<long long, float, int>> JPetSinogram::sinogram(matrix<int> emissionMatrix) {
//   std::vector<std::tuple<long long, float, int>> result; // value, theta, s
//   for(int i = 0; i < emissionMatrix.size1(); i++) {
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 0., emissionMatrix), 0., i));
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 90., emissionMatrix), 90., i));
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 45., emissionMatrix), 45., i));
//   }
//   /*
//   for(int i = 0; i < emissionMatrix.size1() * 2 - 1; i++) {
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 45., emissionMatrix), 45.));
//   }*/
//   return result;
// }
  typedef std::shared_ptr<double[]> ManagedDouble;
  typedef std::shared_ptr<ManagedDouble[]> resultType;

resultType JPetSinogram::sinogram(matrix<int> emissionMatrix, int views, int scans) {
  int i;
  i=0;
  auto proj = std::shared_ptr<ManagedDouble[]>(new ManagedDouble[views]);
  //std::shared_ptr<double**> proj(new double*[views]);
  for(int k = 0; k < views; k++) {
    (*proj)[k] = ManagedDouble(new double[scans]);
  }

  double pos, val, Aleft, Aright;
  int x, y, Xcenter, Ycenter, Ileft, Iright;
  std::unique_ptr<double[]>  sintab(new double[views]);
  std::unique_ptr<double[]>  costab(new double[views]);

  int S=0;
  int inputimgsize = emissionMatrix.size1();

  float phi = 0., stepsize = 0.;
  int ang1 = 0, ang2 = 180;

  for (phi=ang1;phi<ang2;phi=phi+stepsize){
      sintab[i] = std::sin((double) phi * M_PI / 180 - M_PI/2);
      costab[i] = std::cos((double) phi * M_PI / 180 - M_PI/2);
      i++;
  }

  // Project each pixel in the image
  Xcenter = inputimgsize / 2;
  Ycenter = inputimgsize / 2;
  i=0;
  //if no. scans is greater than the image width, then scale will be <1

  double scale = inputimgsize*1.42/scans;

  int N=0; val = 0;
  double weight = 0;
  double sang = std::sqrt(2)/2;
  double progr=0;
  bool fast = false;
  for (phi=ang1;phi<ang2;phi=phi+stepsize){
      double a = -costab[i]/sintab[i] ;
      double aa = 1/a;
      if (std::abs(sintab[i]) > sang){
          for (S=0;S<scans;S++){
              N = S - scans/2;
              double b = (N - costab[i] - sintab[i]) / sintab[i];
              b =  b * scale;

              for (x = -Xcenter; x < Xcenter; x++){
                  if (fast == true){
                      y = (int) std::round(a*x + b);

                      if (y >= -Xcenter && y < Xcenter )
                          val += emissionMatrix((x+Xcenter),(y+Ycenter));

                  } else {
                      y = (int) std::round(a*x + b);
                      weight = std::abs((a*x + b) - std::ceil(a*x + b));

                      if (y >= -Xcenter && y+1 < Xcenter )
                          val += (1-weight) * emissionMatrix((x+Xcenter),(y+Ycenter))
                                  + weight * emissionMatrix((x+Xcenter), (y+Ycenter+1));

                  }
              } (*(*proj)[i])[S] = val/std::abs(sintab[i]); val=0;

          }
      }
      if (std::abs(sintab[i]) <= sang){
          for (S=0;S<scans;S++){
              N = S - scans/2;
              double bb = (N - costab[i] - sintab[i]) / costab[i];
              bb = bb * scale;
              //IJ.write("bb="+bb+" ");
              for (y = -Ycenter; y < Ycenter; y++) {
                  if (fast ==true){
                      x = (int) std::round(aa*y + bb);
                      if (x >= -Xcenter && x < Xcenter )
                          val += emissionMatrix(x+Xcenter, y+Ycenter);
                  } else {
                      x = (int) std::round(aa*y + bb);
                      weight = std::abs((aa*y + bb) - std::ceil(aa*y + bb));

                      if (x >= -Xcenter && x+1 < Xcenter )
                          val += (1-weight) * emissionMatrix((x+Xcenter), (y+Ycenter))
                                  + weight * emissionMatrix((x+Xcenter+1), (y+Ycenter));

                  }
              } (*(*proj)[i])[S] = val/std::abs(costab[i]); val=0;

          }

      } i++;
  }
  i=0;
  normalize2DArray(proj, views, scans, 0, 255);

  return proj;
}

void JPetSinogram::normalize2DArray(resultType data, int imax, int jmax, double min, double max) {
  double datamax = (*(*data)[0])[0];
  double datamin = (*(*data)[0])[0];
  for (int i = 0; i < imax; i++ ) {
    for ( int j = 0; j < jmax; j++ ) {
      if((*(*data)[i])[j] < 0) (*(*data)[i])[j] = 0;
      if((*(*data)[i])[j] > max) datamax = (*(*data)[i])[j];
      if ((*(*data)[i])[j] < min) datamin = (*(*data)[i])[j];
    }
  }
  for ( int i = 0; i < imax; i++ ) {
    for ( int j = 0; j < jmax; j++ ) {
      (*(*data)[i])[j] = (double) ((((*(*data)[i])[j]-datamin) * (max))/datamax);
    }
  }
}<commit_msg>Change smart pointers to vector of vectors<commit_after>#include "./JPetSinogram.h"
#include <boost/numeric/ublas/matrix.hpp>
#include <vector>
#include <utility>
#include <cmath> //for sin and cos
using namespace boost::numeric::ublas;

JPetSinogram::JPetSinogram() { }

JPetSinogram::~JPetSinogram() { }

long long JPetSinogram::forwardProjection(float s, float theta, matrix<int> emissionMatrix) {
  long long sum = 0;

  if(s == 0)
    return sum; // not implemented yet

  if(theta == 90) {
    for(unsigned int i = 0; i < emissionMatrix.size1(); i++) {
      sum += emissionMatrix(i, s);
    }
  } else {
    //prosta prostopadła Ax + By + C = 0
    //w zmiennych biegunowych: x * cos(theta) + y * sin(theta) - s = 0
    //prostopadła x * (-sin(theta)) + y * cos(theta) + C = 0
    int x = std::floor(std::cos(-theta) * s);
    int y = -std::floor(std::sin(-theta) * s);
    float theta2 = 90 / emissionMatrix.size1();
    std::cout << "x: " << x << " y: " << y << " theta2: " << theta2 << std::endl;
    while(x >= 0 && y >= 0 && x < emissionMatrix.size1() && y < emissionMatrix.size2()) {
      sum += emissionMatrix(x, y);
      s++;
      x = std::floor(std::cos(-theta) * s);
      y = -std::round(std::sin(-theta) * s);
      std::cout << "x: " << x << " y: " << y << std::endl;
      //float cos = std::cos(theta2 - theta);
      //float r = s / cos;
//
      //x = std::round(std::cos(theta2) * r);
      //y = std::round(std::sin(theta2) * r);
      //std::cout << "x: " << x << " y: " << y << " theta2: " << theta2  << " r: " << r \
      //<< " cos " << cos << std::endl;
      //theta2 += 90 / emissionMatrix.size1();
    }
  }

  /*if(theta == 0) {
    for(unsigned int i = 0; i < emissionMatrix.size2(); i++) {
      sum += emissionMatrix(s, i);
    }
  } else if(theta == 90) {
    for(unsigned int i = 0; i < emissionMatrix.size1(); i++) {
      sum += emissionMatrix(i, s);
    }
  } else if(theta == 45) {
    unsigned int j = (emissionMatrix.size2() - 1) - s < 0 ? 0 : (emissionMatrix.size2() - 1) - s;
    unsigned int i = (emissionMatrix.size2() - 1) - s < 0 ? - ((emissionMatrix.size2() - 1 - s)) : 0;// select row, start from upper right corner
    for(; j < emissionMatrix.size2(); j++) { //-1 bcs matrix start from 0
      if(i < emissionMatrix.size1()) {
        sum += emissionMatrix(i, j);
        i++;
      }
      else { } // exception
    }

  }*/
  std::cout << "s: " << s << " theta: " << theta << " sum: " << sum << std::endl;
  return sum;
}

// std::vector<std::tuple<long long, float, int>> JPetSinogram::sinogram(matrix<int> emissionMatrix) {
//   std::vector<std::tuple<long long, float, int>> result; // value, theta, s
//   for(int i = 0; i < emissionMatrix.size1(); i++) {
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 0., emissionMatrix), 0., i));
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 90., emissionMatrix), 90., i));
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 45., emissionMatrix), 45., i));
//   }
//   /*
//   for(int i = 0; i < emissionMatrix.size1() * 2 - 1; i++) {
//     result.push_back(std::tuple<long long, float, int>(forwardProjection(i, 45., emissionMatrix), 45.));
//   }*/
//   return result;
// }
  typedef std::shared_ptr<double[]> ManagedDouble;
  typedef std::vector<std::vector<double>> resultType;

resultType JPetSinogram::sinogram(matrix<int> emissionMatrix, int views, int scans) {
  int i;
  i=0;
  std::vector<std::vector<double>> proj(views, std::vector<double>(scans));
  //resultType proj = resultType(new ManagedDouble[views]);
  //std::shared_ptr<double**> proj(new double*[views]);
  //for(int k = 0; k < views; k++) {
  //  proj[k] = ManagedDouble(new double[scans]);
  //}

  double pos, val, Aleft, Aright;
  int x, y, Xcenter, Ycenter, Ileft, Iright;
  std::unique_ptr<double[]>  sintab(new double[views]);
  std::unique_ptr<double[]>  costab(new double[views]);

  int S=0;
  int inputimgsize = emissionMatrix.size1();

  float phi = 0., stepsize = 0.;
  int ang1 = 0, ang2 = 180;
  stepsize = (ang2 - ang1) / views;
  for (phi=ang1;phi<ang2;phi=phi+stepsize){
      sintab[i] = std::sin((double) phi * M_PI / 180 - M_PI/2);
      costab[i] = std::cos((double) phi * M_PI / 180 - M_PI/2);
      i++;
  }

  // Project each pixel in the image
  Xcenter = inputimgsize / 2;
  Ycenter = inputimgsize / 2;
  i=0;
  //if no. scans is greater than the image width, then scale will be <1

  double scale = inputimgsize*1.42/scans;

  int N=0; val = 0;
  double weight = 0;
  double sang = std::sqrt(2)/2;
  double progr=0;
  bool fast = false;
  for (phi=ang1;phi<ang2;phi=phi+stepsize){
      double a = -costab[i]/sintab[i] ;
      double aa = 1/a;
      if (std::abs(sintab[i]) > sang){
          for (S=0;S<scans;S++){
              N = S - scans/2;
              double b = (N - costab[i] - sintab[i]) / sintab[i];
              b =  b * scale;

              for (x = -Xcenter; x < Xcenter; x++){
                  if (fast == true){
                      y = (int) std::round(a*x + b);

                      if (y >= -Xcenter && y < Xcenter )
                          val += emissionMatrix((x+Xcenter),(y+Ycenter));

                  } else {
                      y = (int) std::round(a*x + b);
                      weight = std::abs((a*x + b) - std::ceil(a*x + b));

                      if (y >= -Xcenter && y+1 < Xcenter )
                          val += (1-weight) * emissionMatrix((x+Xcenter),(y+Ycenter))
                                  + weight * emissionMatrix((x+Xcenter), (y+Ycenter+1));

                  }
              } proj[i][S] = val/std::abs(sintab[i]); val=0;

          }
      }
      if (std::abs(sintab[i]) <= sang){
          for (S=0;S<scans;S++){
              N = S - scans/2;
              double bb = (N - costab[i] - sintab[i]) / costab[i];
              bb = bb * scale;
              //IJ.write("bb="+bb+" ");
              for (y = -Ycenter; y < Ycenter; y++) {
                  if (fast ==true){
                      x = (int) std::round(aa*y + bb);
                      if (x >= -Xcenter && x < Xcenter )
                          val += emissionMatrix(x+Xcenter, y+Ycenter);
                  } else {
                      x = (int) std::round(aa*y + bb);
                      weight = std::abs((aa*y + bb) - std::ceil(aa*y + bb));

                      if (x >= -Xcenter && x+1 < Xcenter )
                          val += (1-weight) * emissionMatrix((x+Xcenter), (y+Ycenter))
                                  + weight * emissionMatrix((x+Xcenter+1), (y+Ycenter));

                  }
              } proj[i][S] = val/std::abs(costab[i]); val=0;

          }

      } i++;
  }
  i=0;
  normalize2DArray(proj, views, scans, 0, 255);

  return proj;
}

void JPetSinogram::normalize2DArray(resultType &data, int imax, int jmax, double min, double max) {
  double datamax = data[0][0];
  double datamin = data[0][0];
  for (int i = 0; i < imax; i++ ) {
    for ( int j = 0; j < jmax; j++ ) {
      if(data[i][j] < 0) data[i][j] = 0;
      if(data[i][j] > max) datamax = data[i][j];
      if(data[i][j] < min) datamin = data[i][j];
    }
  }
  for ( int i = 0; i < imax; i++ ) {
    for ( int j = 0; j < jmax; j++ ) {
      data[i][j] = (double) (((data[i][j]-datamin) * (max))/datamax);
    }
  }
}<|endoftext|>


<commit_before>/***********************************************************************
    filename:   CEGUIOgreTexture.cpp
    created:    Tue Feb 17 2009
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUIOgreTexture.h"
#include "CEGUIExceptions.h"
#include "CEGUISystem.h"
#include "CEGUIImageCodec.h"
#include <OgreTextureManager.h>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
// Internal function that reverses all bytes in a buffer
void _byteSwap(unsigned char* b, int n)
{
    register int i = 0;
    register int j = n-1;
    while (i < j)
        std::swap(b[i++], b[j--]);
}
#define byteSwap(x) _byteSwap((unsigned char*) &x,sizeof(x))

//----------------------------------------------------------------------------//
uint32 OgreTexture::d_textureNumber = 0;

//----------------------------------------------------------------------------//
const Size& OgreTexture::getSize() const
{
    return d_size;
}

//----------------------------------------------------------------------------//
const Size& OgreTexture::getOriginalDataSize() const
{
    return d_dataSize;
}

//----------------------------------------------------------------------------//
const Vector2& OgreTexture::getTexelScaling() const
{
    return d_texelScaling;
}

//----------------------------------------------------------------------------//
void OgreTexture::loadFromFile(const String& filename,
                               const String& resourceGroup)
{
    // get and check existence of CEGUI::System object
    System* sys = System::getSingletonPtr();
    if (!sys)
        throw RendererException("OgreTexture::loadFromFile: "
                                "CEGUI::System object has not been created!");

    // load file to memory via resource provider
    RawDataContainer texFile;
    sys->getResourceProvider()->loadRawDataContainer(filename, texFile,
                                                     resourceGroup);

    Texture* res = sys->getImageCodec().load(texFile, this);

    // unload file data buffer
    sys->getResourceProvider()->unloadRawDataContainer(texFile);

    // throw exception if data was load loaded to texture.
    if (!res)
        throw RendererException("OgreTexture::loadFromFile: " +
                                sys->getImageCodec().getIdentifierString()+
                                " failed to load image '" + filename + "'.");
}

//----------------------------------------------------------------------------//
void OgreTexture::loadFromMemory(const void* buffer, const Size& buffer_size,
                                 PixelFormat pixel_format)
{
    using namespace Ogre;

    // get rid of old texture
    freeOgreTexture();

    // wrap input buffer with an Ogre data stream
    const size_t pixel_size = pixel_format == PF_RGBA ? 4 : 3;
    const size_t byte_size = buffer_size.d_width * buffer_size.d_height *
                                pixel_size;

#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
    // FIXME: I think this leaks memory, though need to check!
    unsigned char* swapped_buffer = new unsigned char[byte_size];
    memcpy(swapped_buffer, buffer, byte_size);

    for (size_t i = 0; i < byte_size; i += pixel_size)
        _byteSwap(&swapped_buffer[i], pixel_size);

    DataStreamPtr odc(new MemoryDataStream(static_cast<void*>(swapped_buffer),
                                           byte_size, false));
#else
    DataStreamPtr odc(new MemoryDataStream(const_cast<void*>(buffer),
                                           byte_size, false));
#endif

    // get pixel type for the target texture.
    Ogre::PixelFormat target_fmt =
        (pixel_format == PF_RGBA) ? Ogre::PF_A8B8G8R8 : Ogre::PF_B8G8R8;

    // try to create a Ogre::Texture from the input data
    d_texture = TextureManager::getSingleton().loadRawData(
        getUniqueName(), "General", odc,
        buffer_size.d_width, buffer_size.d_height,
        target_fmt, TEX_TYPE_2D, 0, 1.0f);

    // throw exception if no texture was able to be created
    if (d_texture.isNull())
        throw RendererException("OgreTexture::loadFromMemory: Failed to create "
                                "Texture object from memory.");

    d_size.d_width = d_texture->getWidth();
    d_size.d_height = d_texture->getHeight();
    d_dataSize = buffer_size;
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
void OgreTexture::saveToMemory(void* buffer)
{
    // TODO:
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture() :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const String& filename, const String& resourceGroup) :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
    loadFromFile(filename, resourceGroup);
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const Size& sz) :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
    // TODO:
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(Ogre::TexturePtr& tex, bool take_ownership) :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
    setOgreTexture(tex, take_ownership);
}

//----------------------------------------------------------------------------//
OgreTexture::~OgreTexture()
{
    freeOgreTexture();
}

//----------------------------------------------------------------------------//
void OgreTexture::freeOgreTexture()
{
    if (!d_texture.isNull() && !d_isLinked)
        Ogre::TextureManager::getSingleton().remove(d_texture->getHandle());

    d_texture.setNull();
}

//----------------------------------------------------------------------------//
Ogre::String OgreTexture::getUniqueName()
{
    Ogre::StringUtil::StrStreamType strstream;
    strstream << "_cegui_ogre_" << d_textureNumber++;

    return strstream.str();
}

//----------------------------------------------------------------------------//
void OgreTexture::updateCachedScaleValues()
{
    //
    // calculate what to use for x scale
    //
    const float orgW = d_dataSize.d_width;
    const float texW = d_size.d_width;

    // if texture and original data width are the same, scale is based
    // on the original size.
    // if texture is wider (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_x = 1.0f / ((orgW == texW) ? orgW : texW);

    //
    // calculate what to use for y scale
    //
    const float orgH = d_dataSize.d_height;
    const float texH = d_size.d_height;

    // if texture and original data height are the same, scale is based
    // on the original size.
    // if texture is taller (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_y = 1.0f / ((orgH == texH) ? orgH : texH);
}

//----------------------------------------------------------------------------//
void OgreTexture::setOgreTexture(Ogre::TexturePtr texture, bool take_ownership)
{
    freeOgreTexture();

    d_texture = texture;
    d_isLinked = !take_ownership;

    if (!d_texture.isNull())
    {
        d_size.d_width = d_texture->getWidth();
        d_size.d_height= d_texture->getHeight();
        d_dataSize = d_size;
    }
    else
        d_size = d_dataSize = Size(0, 0);

    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
Ogre::TexturePtr OgreTexture::getOgreTexture() const
{
    return d_texture;
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<commit_msg>ADD: Implement missing parts in Ogre renderer.<commit_after>/***********************************************************************
    filename:   CEGUIOgreTexture.cpp
    created:    Tue Feb 17 2009
    author:     Paul D Turner
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
 *
 *   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 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 "CEGUIOgreTexture.h"
#include "CEGUIExceptions.h"
#include "CEGUISystem.h"
#include "CEGUIImageCodec.h"
#include <OgreTextureManager.h>
#include <OgreHardwarePixelBuffer.h>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
// Internal function that reverses all bytes in a buffer
void _byteSwap(unsigned char* b, int n)
{
    register int i = 0;
    register int j = n-1;
    while (i < j)
        std::swap(b[i++], b[j--]);
}
#define byteSwap(x) _byteSwap((unsigned char*) &x,sizeof(x))

//----------------------------------------------------------------------------//
uint32 OgreTexture::d_textureNumber = 0;

//----------------------------------------------------------------------------//
const Size& OgreTexture::getSize() const
{
    return d_size;
}

//----------------------------------------------------------------------------//
const Size& OgreTexture::getOriginalDataSize() const
{
    return d_dataSize;
}

//----------------------------------------------------------------------------//
const Vector2& OgreTexture::getTexelScaling() const
{
    return d_texelScaling;
}

//----------------------------------------------------------------------------//
void OgreTexture::loadFromFile(const String& filename,
                               const String& resourceGroup)
{
    // get and check existence of CEGUI::System object
    System* sys = System::getSingletonPtr();
    if (!sys)
        throw RendererException("OgreTexture::loadFromFile: "
                                "CEGUI::System object has not been created!");

    // load file to memory via resource provider
    RawDataContainer texFile;
    sys->getResourceProvider()->loadRawDataContainer(filename, texFile,
                                                     resourceGroup);

    Texture* res = sys->getImageCodec().load(texFile, this);

    // unload file data buffer
    sys->getResourceProvider()->unloadRawDataContainer(texFile);

    // throw exception if data was load loaded to texture.
    if (!res)
        throw RendererException("OgreTexture::loadFromFile: " +
                                sys->getImageCodec().getIdentifierString()+
                                " failed to load image '" + filename + "'.");
}

//----------------------------------------------------------------------------//
void OgreTexture::loadFromMemory(const void* buffer, const Size& buffer_size,
                                 PixelFormat pixel_format)
{
    using namespace Ogre;

    // get rid of old texture
    freeOgreTexture();

    // wrap input buffer with an Ogre data stream
    const size_t pixel_size = pixel_format == PF_RGBA ? 4 : 3;
    const size_t byte_size = buffer_size.d_width * buffer_size.d_height *
                                pixel_size;

#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
    // FIXME: I think this leaks memory, though need to check!
    unsigned char* swapped_buffer = new unsigned char[byte_size];
    memcpy(swapped_buffer, buffer, byte_size);

    for (size_t i = 0; i < byte_size; i += pixel_size)
        _byteSwap(&swapped_buffer[i], pixel_size);

    DataStreamPtr odc(new MemoryDataStream(static_cast<void*>(swapped_buffer),
                                           byte_size, false));
#else
    DataStreamPtr odc(new MemoryDataStream(const_cast<void*>(buffer),
                                           byte_size, false));
#endif

    // get pixel type for the target texture.
    Ogre::PixelFormat target_fmt =
        (pixel_format == PF_RGBA) ? Ogre::PF_A8B8G8R8 : Ogre::PF_B8G8R8;

    // try to create a Ogre::Texture from the input data
    d_texture = TextureManager::getSingleton().loadRawData(
        getUniqueName(), "General", odc,
        buffer_size.d_width, buffer_size.d_height,
        target_fmt, TEX_TYPE_2D, 0, 1.0f);

    // throw exception if no texture was able to be created
    if (d_texture.isNull())
        throw RendererException("OgreTexture::loadFromMemory: Failed to create "
                                "Texture object from memory.");

    d_size.d_width = d_texture->getWidth();
    d_size.d_height = d_texture->getHeight();
    d_dataSize = buffer_size;
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
void OgreTexture::saveToMemory(void* buffer)
{
    if (d_texture.isNull())
        return;

    Ogre::HardwarePixelBufferSharedPtr src = d_texture->getBuffer();

    if (src.isNull())
        throw RendererException("OgreTexture::saveToMemory: unable to obtain "
                                "hardware pixel buffer pointer.");

    const size_t sz = static_cast<size_t>(d_size.d_width * d_size.d_height) * 4;
    src->readData(0, sz, buffer);
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture() :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const String& filename, const String& resourceGroup) :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
    loadFromFile(filename, resourceGroup);
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(const Size& sz) :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
    using namespace Ogre;

    // try to create a Ogre::Texture with given dimensions
    d_texture = TextureManager::getSingleton().createManual(
                                   getUniqueName(), "General", TEX_TYPE_2D,
                                   sz.d_width, sz.d_height, 0,
                                   Ogre::PF_A8B8G8R8);

    // throw exception if no texture was able to be created
    if (d_texture.isNull())
        throw RendererException("OgreTexture: Failed to create Texture object "
                                "with spcecified size.");

    d_size.d_width = d_texture->getWidth();
    d_size.d_height = d_texture->getHeight();
    d_dataSize = sz;
    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
OgreTexture::OgreTexture(Ogre::TexturePtr& tex, bool take_ownership) :
    d_isLinked(false),
    d_size(0, 0),
    d_dataSize(0, 0),
    d_texelScaling(0, 0)
{
    setOgreTexture(tex, take_ownership);
}

//----------------------------------------------------------------------------//
OgreTexture::~OgreTexture()
{
    freeOgreTexture();
}

//----------------------------------------------------------------------------//
void OgreTexture::freeOgreTexture()
{
    if (!d_texture.isNull() && !d_isLinked)
        Ogre::TextureManager::getSingleton().remove(d_texture->getHandle());

    d_texture.setNull();
}

//----------------------------------------------------------------------------//
Ogre::String OgreTexture::getUniqueName()
{
    Ogre::StringUtil::StrStreamType strstream;
    strstream << "_cegui_ogre_" << d_textureNumber++;

    return strstream.str();
}

//----------------------------------------------------------------------------//
void OgreTexture::updateCachedScaleValues()
{
    //
    // calculate what to use for x scale
    //
    const float orgW = d_dataSize.d_width;
    const float texW = d_size.d_width;

    // if texture and original data width are the same, scale is based
    // on the original size.
    // if texture is wider (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_x = 1.0f / ((orgW == texW) ? orgW : texW);

    //
    // calculate what to use for y scale
    //
    const float orgH = d_dataSize.d_height;
    const float texH = d_size.d_height;

    // if texture and original data height are the same, scale is based
    // on the original size.
    // if texture is taller (and source data was not stretched), scale
    // is based on the size of the resulting texture.
    d_texelScaling.d_y = 1.0f / ((orgH == texH) ? orgH : texH);
}

//----------------------------------------------------------------------------//
void OgreTexture::setOgreTexture(Ogre::TexturePtr texture, bool take_ownership)
{
    freeOgreTexture();

    d_texture = texture;
    d_isLinked = !take_ownership;

    if (!d_texture.isNull())
    {
        d_size.d_width = d_texture->getWidth();
        d_size.d_height= d_texture->getHeight();
        d_dataSize = d_size;
    }
    else
        d_size = d_dataSize = Size(0, 0);

    updateCachedScaleValues();
}

//----------------------------------------------------------------------------//
Ogre::TexturePtr OgreTexture::getOgreTexture() const
{
    return d_texture;
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 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
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/font_engine_freetype.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <sstream>

// icu
#include <unicode/ubidi.h>
#include <unicode/ushape.h>
#include <unicode/schriter.h>
#include <unicode/uversion.h>

namespace mapnik
{
freetype_engine::freetype_engine()
{
    FT_Error error = FT_Init_FreeType( &library_ );
    if (error)
    {
        throw std::runtime_error("can not load FreeType2 library");
    }
}

freetype_engine::~freetype_engine()
{
    FT_Done_FreeType(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    /** only accept files that will be matched by freetype2's `figurefiletype()` */
    std::string const& fn = boost::algorithm::to_lower_copy(file_name);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        /** Plus OSX custom ext */
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

bool freetype_engine::register_font(std::string const& file_name)
{
    if (!boost::filesystem::is_regular_file(file_name) || !is_font_file(file_name)) return false;
#ifdef MAPNIK_THREADSAFE
    mutex::scoped_lock lock(mutex_);
#endif
    FT_Library library;
    FT_Error error = FT_Init_FreeType(&library);
    if (error)
    {
        throw std::runtime_error("Failed to initialize FreeType2 library");
    }

    FT_Face face;
    error = FT_New_Face (library,file_name.c_str(),0,&face);
    if (error)
    {
        FT_Done_FreeType(library);
        return false;
    }
    // some fonts can lack names, skip them
    // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
    if (face->family_name && face->style_name) {
        std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
        name2file_.insert(std::make_pair(name,file_name));
        FT_Done_Face(face);
        FT_Done_FreeType(library);
        return true;
    } else {
        FT_Done_Face(face);
        FT_Done_FreeType(library);
        std::ostringstream s;
        s << "Error: unable to load invalid font file which lacks identifiable family and style name: '"
          << file_name << "'";
        throw std::runtime_error(s.str());
    }
    return true;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
    boost::filesystem::path path(dir);

    if (!boost::filesystem::exists(path))
        return false;

    if (!boost::filesystem::is_directory(path))
        return mapnik::freetype_engine::register_font(dir);

    boost::filesystem::directory_iterator end_itr;
    for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
    {
        if (boost::filesystem::is_directory(*itr) && recurse)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            if (!register_fonts(itr->path().string(), true)) return false;
#else // v2
            if (!register_fonts(itr->string(), true)) return false;
#endif
        }
        else
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            mapnik::freetype_engine::register_font(itr->path().string());
#else // v2
            mapnik::freetype_engine::register_font(itr->string());
#endif
        }
    }
    return true;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    std::map<std::string,std::string>::const_iterator itr;
    for (itr = name2file_.begin();itr!=name2file_.end();++itr)
    {
        names.push_back(itr->first);
    }
    return names;
}

std::map<std::string,std::string> const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    std::map<std::string,std::string>::iterator itr;
    itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;
        FT_Error error = FT_New_Face (library_,itr->second.c_str(),0,&face);

        if (!error)
        {
            return face_ptr (new font_face(face));
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return stroker_ptr(new stroker(s));
    }
    return stroker_ptr();
}

font_face_set::dimension_t font_face_set::character_dimensions(const unsigned c)
{
    std::map<unsigned, dimension_t>::const_iterator itr;
    itr = dimension_cache_.find(c);
    if (itr != dimension_cache_.end()) {
        return itr->second;
    }

    FT_Matrix matrix;
    FT_Vector pen;
    FT_Error  error;

    pen.x = 0;
    pen.y = 0;

    FT_BBox glyph_bbox;
    FT_Glyph image;

    glyph_ptr glyph = get_glyph(c);
    FT_Face face = glyph->get_face()->get_face();

    matrix.xx = (FT_Fixed)( 1 * 0x10000L );
    matrix.xy = (FT_Fixed)( 0 * 0x10000L );
    matrix.yx = (FT_Fixed)( 0 * 0x10000L );
    matrix.yy = (FT_Fixed)( 1 * 0x10000L );

    FT_Set_Transform(face, &matrix, &pen);

    error = FT_Load_Glyph (face, glyph->get_index(), FT_LOAD_NO_HINTING);
    if ( error )
        return dimension_t(0, 0, 0);

    error = FT_Get_Glyph(face->glyph, &image);
    if ( error )
        return dimension_t(0, 0, 0);

    FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox);
    FT_Done_Glyph(image);

    unsigned tempx = face->glyph->advance.x >> 6;

    //std::clog << "glyph: " << glyph_index << " x: " << tempx << " y: " << tempy << std::endl;
    dimension_t dim(tempx, glyph_bbox.yMax, glyph_bbox.yMin);
    //dimension_cache_[c] = dim; would need an default constructor for dimension_t
    dimension_cache_.insert(std::pair<unsigned, dimension_t>(c, dim));
    return dim;
}

void font_face_set::get_string_info(string_info & info)
{
    unsigned width = 0;
    unsigned height = 0;
    UErrorCode err = U_ZERO_ERROR;
    UnicodeString reordered;
    UnicodeString shaped;

    UnicodeString const& ustr = info.get_string();
    int32_t length = ustr.length();

    UBiDi *bidi = ubidi_openSized(length, 0, &err);
    ubidi_setPara(bidi, ustr.getBuffer(), length, UBIDI_DEFAULT_LTR, 0, &err);

    ubidi_writeReordered(bidi, reordered.getBuffer(length),
                         length, UBIDI_DO_MIRRORING, &err);

    reordered.releaseBuffer(length);

    u_shapeArabic(reordered.getBuffer(), length,
                  shaped.getBuffer(length), length,
                  U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
                  U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &err);

    shaped.releaseBuffer(length);

    if (U_SUCCESS(err)) {
        StringCharacterIterator iter(shaped);
        for (iter.setToStart(); iter.hasNext();) {
            UChar ch = iter.nextPostInc();
            dimension_t char_dim = character_dimensions(ch);
            info.add_info(ch, char_dim.width, char_dim.height);
            width += char_dim.width;
            height = (char_dim.height > height) ? char_dim.height : height;
        }
    }

#if (U_ICU_VERSION_MAJOR_NUM*100 + U_ICU_VERSION_MINOR_NUM >= 406)
    if (ubidi_getBaseDirection(ustr.getBuffer(), length) == UBIDI_RTL)
    {
        info.set_rtl(true);
    }
#endif

    ubidi_close(bidi);
    info.set_dimensions(width, height);
}

#ifdef MAPNIK_THREADSAFE
boost::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::string> freetype_engine::name2file_;
}
<commit_msg>adding support for multiple fonts in one font file, for instance .ttc<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 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
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/font_engine_freetype.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <sstream>

// icu
#include <unicode/ubidi.h>
#include <unicode/ushape.h>
#include <unicode/schriter.h>
#include <unicode/uversion.h>

namespace mapnik
{
freetype_engine::freetype_engine()
{
    FT_Error error = FT_Init_FreeType( &library_ );
    if (error)
    {
        throw std::runtime_error("can not load FreeType2 library");
    }
}

freetype_engine::~freetype_engine()
{
    FT_Done_FreeType(library_);
}

bool freetype_engine::is_font_file(std::string const& file_name)
{
    /** only accept files that will be matched by freetype2's `figurefiletype()` */
    std::string const& fn = boost::algorithm::to_lower_copy(file_name);
    return boost::algorithm::ends_with(fn,std::string(".ttf")) ||
        boost::algorithm::ends_with(fn,std::string(".otf")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        boost::algorithm::ends_with(fn,std::string(".pfa")) ||
        boost::algorithm::ends_with(fn,std::string(".pfb")) ||
        boost::algorithm::ends_with(fn,std::string(".ttc")) ||
        /** Plus OSX custom ext */
        boost::algorithm::ends_with(fn,std::string(".dfont"));
}

bool freetype_engine::register_font(std::string const& file_name)
{
    if (!boost::filesystem::is_regular_file(file_name) || !is_font_file(file_name)) return false;
#ifdef MAPNIK_THREADSAFE
    mutex::scoped_lock lock(mutex_);
#endif
    FT_Library library;
    FT_Error error = FT_Init_FreeType(&library);
    if (error)
    {
        throw std::runtime_error("Failed to initialize FreeType2 library");
    }

    FT_Face face;
    // fome font files have multiple fonts in a file
    // the count is in the 'root' face library[0]
    // see the FT_FaceRec in freetype.h
    for ( int i = 0; face == 0 || i < face->num_faces; i++ ) {
        // if face is null then this is the first face
        error = FT_New_Face (library,file_name.c_str(),i,&face);
        if (error)
        {
            FT_Done_FreeType(library);
            return false;
        }
        // some fonts can lack names, skip them
        // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
        if (face->family_name && face->style_name) {
            std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
            name2file_.insert(std::make_pair(name,file_name));
            FT_Done_Face(face);
            //FT_Done_FreeType(library);
            //return true;
        } else {
            FT_Done_Face(face);
            FT_Done_FreeType(library);
            std::ostringstream s;
            s << "Error: unable to load invalid font file which lacks identifiable family and style name: '"
            << file_name << "'";
            throw std::runtime_error(s.str());
        }
    }
    FT_Done_FreeType(library);
    return true;
}

bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
{
    boost::filesystem::path path(dir);

    if (!boost::filesystem::exists(path))
        return false;

    if (!boost::filesystem::is_directory(path))
        return mapnik::freetype_engine::register_font(dir);

    boost::filesystem::directory_iterator end_itr;
    for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
    {
        if (boost::filesystem::is_directory(*itr) && recurse)
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            if (!register_fonts(itr->path().string(), true)) return false;
#else // v2
            if (!register_fonts(itr->string(), true)) return false;
#endif
        }
        else
        {
#if (BOOST_FILESYSTEM_VERSION == 3)
            mapnik::freetype_engine::register_font(itr->path().string());
#else // v2
            mapnik::freetype_engine::register_font(itr->string());
#endif
        }
    }
    return true;
}

std::vector<std::string> freetype_engine::face_names ()
{
    std::vector<std::string> names;
    std::map<std::string,std::string>::const_iterator itr;
    for (itr = name2file_.begin();itr!=name2file_.end();++itr)
    {
        names.push_back(itr->first);
    }
    return names;
}

std::map<std::string,std::string> const& freetype_engine::get_mapping()
{
    return name2file_;
}

face_ptr freetype_engine::create_face(std::string const& family_name)
{
    std::map<std::string,std::string>::iterator itr;
    itr = name2file_.find(family_name);
    if (itr != name2file_.end())
    {
        FT_Face face;
        FT_Error error = FT_New_Face (library_,itr->second.c_str(),0,&face);

        if (!error)
        {
            return face_ptr (new font_face(face));
        }
    }
    return face_ptr();
}

stroker_ptr freetype_engine::create_stroker()
{
    FT_Stroker s;
    FT_Error error = FT_Stroker_New(library_, &s);
    if (!error)
    {
        return stroker_ptr(new stroker(s));
    }
    return stroker_ptr();
}

font_face_set::dimension_t font_face_set::character_dimensions(const unsigned c)
{
    std::map<unsigned, dimension_t>::const_iterator itr;
    itr = dimension_cache_.find(c);
    if (itr != dimension_cache_.end()) {
        return itr->second;
    }

    FT_Matrix matrix;
    FT_Vector pen;
    FT_Error  error;

    pen.x = 0;
    pen.y = 0;

    FT_BBox glyph_bbox;
    FT_Glyph image;

    glyph_ptr glyph = get_glyph(c);
    FT_Face face = glyph->get_face()->get_face();

    matrix.xx = (FT_Fixed)( 1 * 0x10000L );
    matrix.xy = (FT_Fixed)( 0 * 0x10000L );
    matrix.yx = (FT_Fixed)( 0 * 0x10000L );
    matrix.yy = (FT_Fixed)( 1 * 0x10000L );

    FT_Set_Transform(face, &matrix, &pen);

    error = FT_Load_Glyph (face, glyph->get_index(), FT_LOAD_NO_HINTING);
    if ( error )
        return dimension_t(0, 0, 0);

    error = FT_Get_Glyph(face->glyph, &image);
    if ( error )
        return dimension_t(0, 0, 0);

    FT_Glyph_Get_CBox(image, ft_glyph_bbox_pixels, &glyph_bbox);
    FT_Done_Glyph(image);

    unsigned tempx = face->glyph->advance.x >> 6;

    //std::clog << "glyph: " << glyph_index << " x: " << tempx << " y: " << tempy << std::endl;
    dimension_t dim(tempx, glyph_bbox.yMax, glyph_bbox.yMin);
    //dimension_cache_[c] = dim; would need an default constructor for dimension_t
    dimension_cache_.insert(std::pair<unsigned, dimension_t>(c, dim));
    return dim;
}

void font_face_set::get_string_info(string_info & info)
{
    unsigned width = 0;
    unsigned height = 0;
    UErrorCode err = U_ZERO_ERROR;
    UnicodeString reordered;
    UnicodeString shaped;

    UnicodeString const& ustr = info.get_string();
    int32_t length = ustr.length();

    UBiDi *bidi = ubidi_openSized(length, 0, &err);
    ubidi_setPara(bidi, ustr.getBuffer(), length, UBIDI_DEFAULT_LTR, 0, &err);

    ubidi_writeReordered(bidi, reordered.getBuffer(length),
                         length, UBIDI_DO_MIRRORING, &err);

    reordered.releaseBuffer(length);

    u_shapeArabic(reordered.getBuffer(), length,
                  shaped.getBuffer(length), length,
                  U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
                  U_SHAPE_TEXT_DIRECTION_VISUAL_LTR, &err);

    shaped.releaseBuffer(length);

    if (U_SUCCESS(err)) {
        StringCharacterIterator iter(shaped);
        for (iter.setToStart(); iter.hasNext();) {
            UChar ch = iter.nextPostInc();
            dimension_t char_dim = character_dimensions(ch);
            info.add_info(ch, char_dim.width, char_dim.height);
            width += char_dim.width;
            height = (char_dim.height > height) ? char_dim.height : height;
        }
    }

#if (U_ICU_VERSION_MAJOR_NUM*100 + U_ICU_VERSION_MINOR_NUM >= 406)
    if (ubidi_getBaseDirection(ustr.getBuffer(), length) == UBIDI_RTL)
    {
        info.set_rtl(true);
    }
#endif

    ubidi_close(bidi);
    info.set_dimensions(width, height);
}

#ifdef MAPNIK_THREADSAFE
boost::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::string> freetype_engine::name2file_;
}
<|endoftext|>


<commit_before>// Copyright 2011-2012 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "base/hash.h"
#include "base/map-util.h"
#include "base/stl_util.h"
#include "base/random.h"
#include "constraint_solver/constraint_solveri.h"
#include "constraint_solver/constraint_solver.h"
#include "constraint_solver/model.pb.h"

namespace operations_research {
class OneVarLns : public BaseLNS {
 public:
  OneVarLns(const IntVar* const* vars, int size)
      : BaseLNS(vars, size),
        index_(0) {}

  ~OneVarLns() {}

  virtual void InitFragments() { index_ = 0; }

  virtual bool NextFragment(std::vector<int>* fragment) {
    const int size = Size();
    if (index_ < size) {
      fragment->push_back(index_);
      ++index_;
      return true;
    } else {
      return false;
    }
  }

 private:
  int index_;
};

class MoveOneVar: public IntVarLocalSearchOperator {
 public:
  MoveOneVar(const std::vector<IntVar*>& variables)
      : IntVarLocalSearchOperator(variables.data(), variables.size()),
        variable_index_(0),
        move_up_(false) {}

  virtual ~MoveOneVar() {}

 protected:
  // Make a neighbor assigning one variable to its target value.
  virtual bool MakeOneNeighbor() {
    const int64 current_value = OldValue(variable_index_);
    if (move_up_) {
      SetValue(variable_index_, current_value  + 1);
      variable_index_ = (variable_index_ + 1) % Size();
    } else {
      SetValue(variable_index_, current_value  - 1);
    }
    move_up_ = !move_up_;
    return true;
  }

 private:
  virtual void OnStart() {
    CHECK_GE(variable_index_, 0);
    CHECK_LT(variable_index_, Size());
  }

  // Index of the next variable to try to restore
  int64 variable_index_;
  // Direction of the modification.
  bool move_up_;
};

class SumFilter : public IntVarLocalSearchFilter {
 public:
  SumFilter(const IntVar* const* vars, int size) :
      IntVarLocalSearchFilter(vars, size), sum_(0) {}

  ~SumFilter() {}

  virtual void OnSynchronize() {
    sum_ = 0;
    for (int index = 0; index < Size(); ++index) {
      sum_ += Value(index);
    }
  }

  virtual bool Accept(const Assignment* delta,
                      const Assignment* unused_deltadelta) {
    const Assignment::IntContainer& solution_delta = delta->IntVarContainer();
    const int solution_delta_size = solution_delta.Size();

    // The input const Assignment* delta given to Accept() may
    // actually contain "Deactivated" elements, which represent
    // variables that have been freed -- they are not bound to a
    // single value anymore. This happens with LNS-type (Large
    // Neighborhood Search) LocalSearchOperator, which are not used in
    // this example as of 2012-01; and we refer the reader to
    // ./routing.cc for an example of such LNS-type operators.
    //
    // For didactical purposes, we will assume for a moment that a
    // LNS-type operator might be applied. The Filter will still be
    // called, but our filter here won't be able to work, since
    // it needs every variable to be bound (i.e. have a fixed value),
    // in the assignment that it considers. Therefore, we include here
    // a snippet of code that will detect if the input assignment is
    // not fully bound. For further details, read ./routing.cc -- but
    // we strongly advise the reader to first try and understand all
    // of this file.
    for (int i = 0; i < solution_delta_size; ++i) {
      if (!solution_delta.Element(i).Activated()) {
        VLOG(1)
            << "Element #" << i << " of the delta assignment given to"
            << " SumFilter::Accept() is not activated (i.e. its variable"
            << " is not bound to a single value anymore). This means that"
            << " we are in a LNS phase, and the DobbleFilter won't be able"
            << " to filter anything. Returning true.";
        return true;
      }
    }
    int64 new_sum = sum_;
    VLOG(1) << "No LNS, size = " << solution_delta_size;
    for (int index = 0; index < solution_delta_size; ++index) {
      int64 touched_var = -1;
      FindIndex(solution_delta.Element(index).Var(), &touched_var);
      const int64 old_value = Value(touched_var);
      const int64 new_value = solution_delta.Element(index).Value();
      new_sum += new_value - old_value;
    }
    VLOG(1) << "new sum = " << new_sum << ", old sum = " << sum_;
    return new_sum < sum_;
  }

 private:
  int64 sum_;
};

void BasicLns() {
  LOG(INFO) << "Basic LNS";
  Solver s("Sample");
  vector<IntVar*> vars;
  s.MakeIntVarArray(4, 0, 4, &vars);
  IntVar* const sum_var = s.MakeSum(vars)->Var();
  OptimizeVar* const obj = s.MakeMinimize(sum_var, 1);
  DecisionBuilder* const db =
      s.MakePhase(vars,
                  Solver::CHOOSE_FIRST_UNBOUND,
                  Solver::ASSIGN_MAX_VALUE);
  OneVarLns one_var_lns(vars.data(), vars.size());
  LocalSearchPhaseParameters* const ls_params =
      s.MakeLocalSearchPhaseParameters(&one_var_lns, db);
  DecisionBuilder* const ls = s.MakeLocalSearchPhase(vars, db, ls_params);
  SolutionCollector* const collector = s.MakeLastSolutionCollector();
  collector->Add(vars);
  collector->AddObjective(sum_var);
  SearchMonitor* const log = s.MakeSearchLog(1000, obj);
  s.Solve(ls, collector, obj, log);
  LOG(INFO) << "Objective value = " << collector->objective_value(0);
}

void BasicLs() {
  LOG(INFO) << "Basic LS";
  Solver s("Sample");
  vector<IntVar*> vars;
  s.MakeIntVarArray(4, 0, 4, &vars);
  IntVar* const sum_var = s.MakeSum(vars)->Var();
  OptimizeVar* const obj = s.MakeMinimize(sum_var, 1);
  DecisionBuilder* const db =
      s.MakePhase(vars,
                  Solver::CHOOSE_FIRST_UNBOUND,
                  Solver::ASSIGN_MAX_VALUE);
  MoveOneVar one_var_ls(vars);
  LocalSearchPhaseParameters* const ls_params =
      s.MakeLocalSearchPhaseParameters(&one_var_ls, db);
  DecisionBuilder* const ls = s.MakeLocalSearchPhase(vars, db, ls_params);
  SolutionCollector* const collector = s.MakeLastSolutionCollector();
  collector->Add(vars);
  collector->AddObjective(sum_var);
  SearchMonitor* const log = s.MakeSearchLog(1000, obj);
  s.Solve(ls, collector, obj, log);
  LOG(INFO) << "Objective value = " << collector->objective_value(0);
}

void BasicLsWithFilter() {
  LOG(INFO) << "Basic LS with Filter";
  Solver s("Sample");
  vector<IntVar*> vars;
  s.MakeIntVarArray(4, 0, 4, &vars);
  IntVar* const sum_var = s.MakeSum(vars)->Var();
  OptimizeVar* const obj = s.MakeMinimize(sum_var, 1);
  DecisionBuilder* const db =
      s.MakePhase(vars,
                  Solver::CHOOSE_FIRST_UNBOUND,
                  Solver::ASSIGN_MAX_VALUE);
  MoveOneVar one_var_ls(vars);
  std::vector<LocalSearchFilter*> filters;
  filters.push_back(s.RevAlloc(new SumFilter(vars.data(), vars.size())));

  LocalSearchPhaseParameters* const ls_params =
      s.MakeLocalSearchPhaseParameters(&one_var_ls, db, NULL, filters);
  DecisionBuilder* const ls = s.MakeLocalSearchPhase(vars, db, ls_params);
  SolutionCollector* const collector = s.MakeLastSolutionCollector();
  collector->Add(vars);
  collector->AddObjective(sum_var);
  SearchMonitor* const log = s.MakeSearchLog(1000, obj);
  s.Solve(ls, collector, obj, log);
  LOG(INFO) << "Objective value = " << collector->objective_value(0);
}
}  //namespace operations_research

int main(int argc, char** argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  operations_research::BasicLns();
  operations_research::BasicLs();
  operations_research::BasicLsWithFilter();
  return 0;
}

<commit_msg>compilation fix<commit_after>// Copyright 2011-2012 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "base/hash.h"
#include "base/map-util.h"
#include "base/stl_util.h"
#include "base/random.h"
#include "constraint_solver/constraint_solveri.h"
#include "constraint_solver/constraint_solver.h"
#include "constraint_solver/model.pb.h"

namespace operations_research {
class OneVarLns : public BaseLNS {
 public:
  OneVarLns(const IntVar* const* vars, int size)
      : BaseLNS(vars, size),
        index_(0) {}

  ~OneVarLns() {}

  virtual void InitFragments() { index_ = 0; }

  virtual bool NextFragment(std::vector<int>* fragment) {
    const int size = Size();
    if (index_ < size) {
      fragment->push_back(index_);
      ++index_;
      return true;
    } else {
      return false;
    }
  }

 private:
  int index_;
};

class MoveOneVar: public IntVarLocalSearchOperator {
 public:
  MoveOneVar(const std::vector<IntVar*>& variables)
      : IntVarLocalSearchOperator(variables.data(), variables.size()),
        variable_index_(0),
        move_up_(false) {}

  virtual ~MoveOneVar() {}

 protected:
  // Make a neighbor assigning one variable to its target value.
  virtual bool MakeOneNeighbor() {
    const int64 current_value = OldValue(variable_index_);
    if (move_up_) {
      SetValue(variable_index_, current_value  + 1);
      variable_index_ = (variable_index_ + 1) % Size();
    } else {
      SetValue(variable_index_, current_value  - 1);
    }
    move_up_ = !move_up_;
    return true;
  }

 private:
  virtual void OnStart() {
    CHECK_GE(variable_index_, 0);
    CHECK_LT(variable_index_, Size());
  }

  // Index of the next variable to try to restore
  int64 variable_index_;
  // Direction of the modification.
  bool move_up_;
};

class SumFilter : public IntVarLocalSearchFilter {
 public:
  SumFilter(const IntVar* const* vars, int size) :
      IntVarLocalSearchFilter(vars, size), sum_(0) {}

  ~SumFilter() {}

  virtual void OnSynchronize() {
    sum_ = 0;
    for (int index = 0; index < Size(); ++index) {
      sum_ += Value(index);
    }
  }

  virtual bool Accept(const Assignment* delta,
                      const Assignment* unused_deltadelta) {
    const Assignment::IntContainer& solution_delta = delta->IntVarContainer();
    const int solution_delta_size = solution_delta.Size();

    // The input const Assignment* delta given to Accept() may
    // actually contain "Deactivated" elements, which represent
    // variables that have been freed -- they are not bound to a
    // single value anymore. This happens with LNS-type (Large
    // Neighborhood Search) LocalSearchOperator, which are not used in
    // this example as of 2012-01; and we refer the reader to
    // ./routing.cc for an example of such LNS-type operators.
    //
    // For didactical purposes, we will assume for a moment that a
    // LNS-type operator might be applied. The Filter will still be
    // called, but our filter here won't be able to work, since
    // it needs every variable to be bound (i.e. have a fixed value),
    // in the assignment that it considers. Therefore, we include here
    // a snippet of code that will detect if the input assignment is
    // not fully bound. For further details, read ./routing.cc -- but
    // we strongly advise the reader to first try and understand all
    // of this file.
    for (int i = 0; i < solution_delta_size; ++i) {
      if (!solution_delta.Element(i).Activated()) {
        VLOG(1)
            << "Element #" << i << " of the delta assignment given to"
            << " SumFilter::Accept() is not activated (i.e. its variable"
            << " is not bound to a single value anymore). This means that"
            << " we are in a LNS phase, and the DobbleFilter won't be able"
            << " to filter anything. Returning true.";
        return true;
      }
    }
    int64 new_sum = sum_;
    VLOG(1) << "No LNS, size = " << solution_delta_size;
    for (int index = 0; index < solution_delta_size; ++index) {
      int64 touched_var = -1;
      FindIndex(solution_delta.Element(index).Var(), &touched_var);
      const int64 old_value = Value(touched_var);
      const int64 new_value = solution_delta.Element(index).Value();
      new_sum += new_value - old_value;
    }
    VLOG(1) << "new sum = " << new_sum << ", old sum = " << sum_;
    return new_sum < sum_;
  }

 private:
  int64 sum_;
};

void BasicLns() {
  LOG(INFO) << "Basic LNS";
  Solver s("Sample");
  std::vector<IntVar*> vars;
  s.MakeIntVarArray(4, 0, 4, &vars);
  IntVar* const sum_var = s.MakeSum(vars)->Var();
  OptimizeVar* const obj = s.MakeMinimize(sum_var, 1);
  DecisionBuilder* const db =
      s.MakePhase(vars,
                  Solver::CHOOSE_FIRST_UNBOUND,
                  Solver::ASSIGN_MAX_VALUE);
  OneVarLns one_var_lns(vars.data(), vars.size());
  LocalSearchPhaseParameters* const ls_params =
      s.MakeLocalSearchPhaseParameters(&one_var_lns, db);
  DecisionBuilder* const ls = s.MakeLocalSearchPhase(vars, db, ls_params);
  SolutionCollector* const collector = s.MakeLastSolutionCollector();
  collector->Add(vars);
  collector->AddObjective(sum_var);
  SearchMonitor* const log = s.MakeSearchLog(1000, obj);
  s.Solve(ls, collector, obj, log);
  LOG(INFO) << "Objective value = " << collector->objective_value(0);
}

void BasicLs() {
  LOG(INFO) << "Basic LS";
  Solver s("Sample");
  std::vector<IntVar*> vars;
  s.MakeIntVarArray(4, 0, 4, &vars);
  IntVar* const sum_var = s.MakeSum(vars)->Var();
  OptimizeVar* const obj = s.MakeMinimize(sum_var, 1);
  DecisionBuilder* const db =
      s.MakePhase(vars,
                  Solver::CHOOSE_FIRST_UNBOUND,
                  Solver::ASSIGN_MAX_VALUE);
  MoveOneVar one_var_ls(vars);
  LocalSearchPhaseParameters* const ls_params =
      s.MakeLocalSearchPhaseParameters(&one_var_ls, db);
  DecisionBuilder* const ls = s.MakeLocalSearchPhase(vars, db, ls_params);
  SolutionCollector* const collector = s.MakeLastSolutionCollector();
  collector->Add(vars);
  collector->AddObjective(sum_var);
  SearchMonitor* const log = s.MakeSearchLog(1000, obj);
  s.Solve(ls, collector, obj, log);
  LOG(INFO) << "Objective value = " << collector->objective_value(0);
}

void BasicLsWithFilter() {
  LOG(INFO) << "Basic LS with Filter";
  Solver s("Sample");
  std::vector<IntVar*> vars;
  s.MakeIntVarArray(4, 0, 4, &vars);
  IntVar* const sum_var = s.MakeSum(vars)->Var();
  OptimizeVar* const obj = s.MakeMinimize(sum_var, 1);
  DecisionBuilder* const db =
      s.MakePhase(vars,
                  Solver::CHOOSE_FIRST_UNBOUND,
                  Solver::ASSIGN_MAX_VALUE);
  MoveOneVar one_var_ls(vars);
  std::vector<LocalSearchFilter*> filters;
  filters.push_back(s.RevAlloc(new SumFilter(vars.data(), vars.size())));

  LocalSearchPhaseParameters* const ls_params =
      s.MakeLocalSearchPhaseParameters(&one_var_ls, db, NULL, filters);
  DecisionBuilder* const ls = s.MakeLocalSearchPhase(vars, db, ls_params);
  SolutionCollector* const collector = s.MakeLastSolutionCollector();
  collector->Add(vars);
  collector->AddObjective(sum_var);
  SearchMonitor* const log = s.MakeSearchLog(1000, obj);
  s.Solve(ls, collector, obj, log);
  LOG(INFO) << "Objective value = " << collector->objective_value(0);
}
}  //namespace operations_research

int main(int argc, char** argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  operations_research::BasicLns();
  operations_research::BasicLs();
  operations_research::BasicLsWithFilter();
  return 0;
}

<|endoftext|>


<commit_before>#include "testing/testing.h"
#include "ParseDatabase.hpp"

#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <string>

using namespace openMVG::exif::sensordb;

static const std::string sDatabase = "sensor_width_camera_database.txt";
TEST(Matching, InvalidDatabase)
{
  std::vector<Datasheet> vec_database;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), "" );

  EXPECT_FALSE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( vec_database.empty() );
}

TEST(Matching, ValidDatabase)
{
  std::vector<Datasheet> vec_database;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( !vec_database.empty() );

}

TEST(Matching, ParseDatabaseSD900)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon PowerShot SD900";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( "Canon", datasheet._brand );
  EXPECT_EQ( "Canon PowerShot SD900", datasheet._model );
  EXPECT_EQ( 7.11, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseA710_IS)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon PowerShot A710 IS";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( "Canon", datasheet._brand );
  EXPECT_EQ( "Canon PowerShot A710 IS", datasheet._model );
  EXPECT_EQ( 5.75, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseNotExist)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "NotExistModel";
  const std::string sBrand = "NotExistBrand";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_FALSE( getInfo( sBrand, sModel, vec_database, datasheet ) );
}

TEST(Matching, ParseDatabaseCanon_EOS_550D)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon EOS 550D";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( 22.3, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseCanon_EOS_5D_Mark_II)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon EOS 5D Mark II";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( 36, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseCanon_EOS_1100D)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon EOS 1100D";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( 22.2, datasheet._sensorSize );
}

/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
/* ************************************************************************* */
<commit_msg>[exif] fix parse database test : Update `Canon EOS 5D Mark II` sensor width<commit_after>#include "testing/testing.h"
#include "ParseDatabase.hpp"

#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

#include <string>

using namespace openMVG::exif::sensordb;

static const std::string sDatabase = "sensor_width_camera_database.txt";
TEST(Matching, InvalidDatabase)
{
  std::vector<Datasheet> vec_database;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), "" );

  EXPECT_FALSE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( vec_database.empty() );
}

TEST(Matching, ValidDatabase)
{
  std::vector<Datasheet> vec_database;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( !vec_database.empty() );

}

TEST(Matching, ParseDatabaseSD900)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon PowerShot SD900";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( "Canon", datasheet._brand );
  EXPECT_EQ( "Canon PowerShot SD900", datasheet._model );
  EXPECT_EQ( 7.11, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseA710_IS)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon PowerShot A710 IS";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( "Canon", datasheet._brand );
  EXPECT_EQ( "Canon PowerShot A710 IS", datasheet._model );
  EXPECT_EQ( 5.75, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseNotExist)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "NotExistModel";
  const std::string sBrand = "NotExistBrand";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_FALSE( getInfo( sBrand, sModel, vec_database, datasheet ) );
}

TEST(Matching, ParseDatabaseCanon_EOS_550D)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon EOS 550D";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( 22.3, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseCanon_EOS_5D_Mark_II)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon EOS 5D Mark II";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( 35.8, datasheet._sensorSize );
}

TEST(Matching, ParseDatabaseCanon_EOS_1100D)
{
  std::vector<Datasheet> vec_database;
  Datasheet datasheet;
  const std::string sfileDatabase = stlplus::create_filespec( std::string(THIS_SOURCE_DIR), sDatabase );
  const std::string sModel = "Canon EOS 1100D";
  const std::string sBrand = "Canon";

  EXPECT_TRUE( parseDatabase( sfileDatabase, vec_database ) );
  EXPECT_TRUE( getInfo( sBrand, sModel, vec_database, datasheet ) );
  EXPECT_EQ( 22.2, datasheet._sensorSize );
}

/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
/* ************************************************************************* */
<|endoftext|>


<commit_before>namespace factor {

// It is up to the caller to fill in the object's fields in a
// meaningful fashion!

// Allocates memory
inline code_block* factor_vm::allot_code_block(cell size,
                                               code_block_type type) {
  cell block_size = size + sizeof(code_block);
  code_block* block = code->allocator->allot(block_size);

  if (block == NULL) {
    // If allocation failed, do a full GC and compact the code heap.
    // A full GC that occurs as a result of the data heap filling up does not
    // trigger a compaction. This setup ensures that most GCs do not compact
    // the code heap, but if the code fills up, it probably means it will be
    // fragmented after GC anyway, so its best to compact.
    primitive_compact_gc();
    block = code->allocator->allot(block_size);

    // Insufficient room even after code GC, give up
    if (block == NULL) {
      std::cout << "Code heap used: " << code->allocator->occupied_space()
                << "\n";
      std::cout << "Code heap free: " << code->allocator->free_space << "\n";
      std::cout << "Request       : " << block_size << "\n";
      fatal_error("Out of memory in allot_code_block", 0);
    }
  }

  // next time we do a minor GC, we have to trace this code block, since
  // the fields of the code_block struct might point into nursery or aging
  this->code->write_barrier(block);

  block->set_type(type);
  return block;
}

// Allocates memory
inline object* factor_vm::allot_large_object(cell type, cell size) {
  // If tenured space does not have enough room, collect and compact
  cell required_free = size + data->high_water_mark();
  if (!data->tenured->can_allot_p(required_free)) {
    primitive_compact_gc();

    // If it still won't fit, grow the heap
    if (!data->tenured->can_allot_p(required_free)) {
      gc(COLLECT_GROWING_DATA_HEAP_OP, size);
    }
  }
  object* obj = data->tenured->allot(size);

  // Allows initialization code to store old->new pointers
  // without hitting the write barrier in the common case of
  // a nursery allocation
  write_barrier(obj, size);

  obj->initialize(type);
  return obj;
}

// Allocates memory
inline object* factor_vm::allot_object(cell type, cell size) {
  FACTOR_ASSERT(!current_gc);

  bump_allocator *nursery = data->nursery;

  // If the object is bigger than the nursery, allocate it in tenured space
  if (size >= nursery->size)
    return allot_large_object(type, size);

  // If the object is smaller than the nursery, allocate it in the nursery,
  // after a GC if needed
  if (nursery->here + size > nursery->end)
    primitive_minor_gc();

  object* obj = nursery->allot(size);
  obj->initialize(type);

  return obj;
}

}
<commit_msg>vm/allot.hpp: Print more room info when allot() fails.<commit_after>namespace factor {

// It is up to the caller to fill in the object's fields in a
// meaningful fashion!

// Allocates memory
inline code_block* factor_vm::allot_code_block(cell size,
                                               code_block_type type) {
  cell block_size = size + sizeof(code_block);
  code_block* block = code->allocator->allot(block_size);

  if (block == NULL) {
    // If allocation failed, do a full GC and compact the code heap.
    // A full GC that occurs as a result of the data heap filling up does not
    // trigger a compaction. This setup ensures that most GCs do not compact
    // the code heap, but if the code fills up, it probably means it will be
    // fragmented after GC anyway, so its best to compact.
    primitive_compact_gc();
    block = code->allocator->allot(block_size);

    // Insufficient room even after code GC, give up
    if (block == NULL) {
      std::cout << "Code heap used:               " << code->allocator->occupied_space() << "\n";
      std::cout << "Code heap free:               " << code->allocator->free_space << "\n";
      std::cout << "Code heap free_block_count:   " << code->allocator->free_block_count << "\n";
      std::cout << "Code heap largest_free_block: " << code->allocator->largest_free_block() << "\n";
      std::cout << "Request       : " << block_size << "\n";
      fatal_error("Out of memory in allot_code_block", 0);
    }
  }

  // next time we do a minor GC, we have to trace this code block, since
  // the fields of the code_block struct might point into nursery or aging
  this->code->write_barrier(block);

  block->set_type(type);
  return block;
}

// Allocates memory
inline object* factor_vm::allot_large_object(cell type, cell size) {
  // If tenured space does not have enough room, collect and compact
  cell required_free = size + data->high_water_mark();
  if (!data->tenured->can_allot_p(required_free)) {
    primitive_compact_gc();

    // If it still won't fit, grow the heap
    if (!data->tenured->can_allot_p(required_free)) {
      gc(COLLECT_GROWING_DATA_HEAP_OP, size);
    }
  }
  object* obj = data->tenured->allot(size);

  // Allows initialization code to store old->new pointers
  // without hitting the write barrier in the common case of
  // a nursery allocation
  write_barrier(obj, size);

  obj->initialize(type);
  return obj;
}

// Allocates memory
inline object* factor_vm::allot_object(cell type, cell size) {
  FACTOR_ASSERT(!current_gc);

  bump_allocator *nursery = data->nursery;

  // If the object is bigger than the nursery, allocate it in tenured space
  if (size >= nursery->size)
    return allot_large_object(type, size);

  // If the object is smaller than the nursery, allocate it in the nursery,
  // after a GC if needed
  if (nursery->here + size > nursery->end)
    primitive_minor_gc();

  object* obj = nursery->allot(size);
  obj->initialize(type);

  return obj;
}

}
<|endoftext|>