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

  Program:   Visualization Toolkit
  Module:    vtkUnicodeString.cxx

-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

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

#include "vtkUnicodeString.h"

#include <vtkObject.h>
#include <utf8.h>

#include <vtkstd/map>
#include <vtkstd/stdexcept>

///////////////////////////////////////////////////////////////////////////
// vtkUnicodeString::const_iterator

vtkUnicodeString::const_iterator::const_iterator()
{
}

vtkUnicodeString::const_iterator::const_iterator(vtkstd::string::const_iterator position) :
  Position(position)
{
}

vtkUnicodeString::value_type vtkUnicodeString::const_iterator::operator*() const
{
  return vtk_utf8::unchecked::peek_next(this->Position);
}

bool vtkUnicodeString::const_iterator::operator==(const const_iterator& rhs) const
{
  return this->Position == rhs.Position;
}

bool vtkUnicodeString::const_iterator::operator!=(const const_iterator& rhs) const
{
  return !(*this == rhs);
}

vtkUnicodeString::const_iterator& vtkUnicodeString::const_iterator::operator++()
{
  vtk_utf8::unchecked::next(this->Position);
  return *this;
}

vtkUnicodeString::const_iterator vtkUnicodeString::const_iterator::operator++(int)
{
  const_iterator result(this->Position);
  vtk_utf8::unchecked::next(this->Position);
  return result;
}

vtkUnicodeString::const_iterator& vtkUnicodeString::const_iterator::operator--()
{
  vtk_utf8::unchecked::prior(this->Position);
  return *this;
}

vtkUnicodeString::const_iterator vtkUnicodeString::const_iterator::operator--(int)
{
  const_iterator result(this->Position);
  vtk_utf8::unchecked::prior(this->Position);
  return result;
}

///////////////////////////////////////////////////////////////////////////
// vtkUnicodeString::back_insert_iterator

// We provide our own implementation of vtkstd::back_insert_iterator for
// use with MSVC 6, where push_back() isn't implemented for vtkstd::string.

class vtkUnicodeString::back_insert_iterator
{
public:
  back_insert_iterator(vtkstd::string& container) :
    Container(&container)
  {
  }

  back_insert_iterator& operator*()
  {
    return *this;
  }

  back_insert_iterator& operator++()
  {
    return *this;
  }

  back_insert_iterator& operator++(int)
  {
    return *this;
  }

  back_insert_iterator& operator=(vtkstd::string::const_reference value)
  {
#if defined(_MSC_VER) && (_MSC_VER < 1300) // MSVC 6
    this->Container->append(1, value);
#else
    this->Container->push_back(value);
#endif
    return *this;
  }

private:
  vtkstd::string* Container;
};

///////////////////////////////////////////////////////////////////////////
// vtkUnicodeString

vtkUnicodeString::vtkUnicodeString()
{
}

vtkUnicodeString::vtkUnicodeString(const vtkUnicodeString& rhs) :
  Storage(rhs.Storage)
{
}

vtkUnicodeString::vtkUnicodeString(size_type count, value_type character)
{
  for(size_type i = 0; i != count; ++i)
    vtk_utf8::append(character, vtkUnicodeString::back_insert_iterator(this->Storage));
}

vtkUnicodeString::vtkUnicodeString(const_iterator first, const_iterator last) :
  Storage(first.Position, last.Position)
{
}

bool vtkUnicodeString::is_utf8(const char* value)
{
  return vtkUnicodeString::is_utf8(vtkstd::string(value ? value : ""));
}

bool vtkUnicodeString::is_utf8(const vtkstd::string& value)
{
  return vtk_utf8::is_valid(value.begin(), value.end());
}

vtkUnicodeString vtkUnicodeString::from_utf8(const char* value)
{
  return vtkUnicodeString::from_utf8(vtkstd::string(value ? value : ""));
}

vtkUnicodeString vtkUnicodeString::from_utf8(const char* begin, const char* end)
{
  vtkUnicodeString result;
  if(vtk_utf8::is_valid(begin, end))
    {
    result.Storage = vtkstd::string(begin, end);
    }
  else
    {
    vtkGenericWarningMacro("vtkUnicodeString::from_utf8(): not a valid UTF-8 string.");
    }
  return result;
}

vtkUnicodeString vtkUnicodeString::from_utf8(const vtkstd::string& value)
{
  vtkUnicodeString result;
  if(vtk_utf8::is_valid(value.begin(), value.end()))
    {
    result.Storage = value;
    }
  else
    {
    vtkGenericWarningMacro("vtkUnicodeString::from_utf8(): not a valid UTF-8 string.");
    }
  return result;
}

vtkUnicodeString vtkUnicodeString::from_utf16(const vtkTypeUInt16* value)
{
  vtkUnicodeString result;

  if(value)
    {
    size_type length = 0;
    while(value[length])
      ++length;

    try
      {
      vtk_utf8::utf16to8(value, value + length, vtkUnicodeString::back_insert_iterator(result.Storage));
      }
    catch(vtk_utf8::invalid_utf16&)
      {
      vtkGenericWarningMacro(<< "vtkUnicodeString::from_utf16(): not a valid UTF-16 string.");
      }
    }

  return result;
}

vtkUnicodeString& vtkUnicodeString::operator=(const vtkUnicodeString& rhs)
{
  if(this == &rhs)
    return *this;

  this->Storage = rhs.Storage;
  return *this;
}

vtkUnicodeString::const_iterator vtkUnicodeString::begin() const
{
  return const_iterator(this->Storage.begin());
}

vtkUnicodeString::const_iterator vtkUnicodeString::end() const
{
  return const_iterator(this->Storage.end());
}

vtkUnicodeString::value_type vtkUnicodeString::at(size_type offset) const
{
  if(offset >= this->character_count())
    throw vtkstd::out_of_range("character out-of-range");

  vtkstd::string::const_iterator iterator = this->Storage.begin();
  vtk_utf8::unchecked::advance(iterator, offset);
  return vtk_utf8::unchecked::peek_next(iterator);
}

vtkUnicodeString::value_type vtkUnicodeString::operator[](size_type offset) const
{
  vtkstd::string::const_iterator iterator = this->Storage.begin();
  vtk_utf8::unchecked::advance(iterator, offset);
  return vtk_utf8::unchecked::peek_next(iterator);
}

const char* vtkUnicodeString::utf8_str() const
{
  return this->Storage.c_str();
}

void vtkUnicodeString::utf8_str(vtkstd::string& result) const
{
  result = this->Storage;
}

vtkstd::vector<vtkTypeUInt16> vtkUnicodeString::utf16_str() const
{
  vtkstd::vector<vtkTypeUInt16> result;
  vtk_utf8::unchecked::utf8to16(this->Storage.begin(), this->Storage.end(), vtkstd::back_inserter(result));
  return result;
}

void vtkUnicodeString::utf16_str(vtkstd::vector<vtkTypeUInt16>& result) const
{
  result.clear();
  vtk_utf8::unchecked::utf8to16(this->Storage.begin(), this->Storage.end(), vtkstd::back_inserter(result));
}

vtkUnicodeString::size_type vtkUnicodeString::byte_count() const
{
  return this->Storage.size();
}

vtkUnicodeString::size_type vtkUnicodeString::character_count() const
{
  return vtk_utf8::unchecked::distance(this->Storage.begin(), this->Storage.end());
}

bool vtkUnicodeString::empty() const
{
  return this->Storage.empty();
}

const vtkUnicodeString::size_type vtkUnicodeString::npos = vtkstd::string::npos;

vtkUnicodeString& vtkUnicodeString::operator+=(value_type value)
{
  this->push_back(value);
  return *this;
}

vtkUnicodeString& vtkUnicodeString::operator+=(const vtkUnicodeString& rhs)
{
  this->append(rhs);
  return *this;
}

void vtkUnicodeString::push_back(value_type character)
{
  try
    {
    vtk_utf8::append(character, vtkUnicodeString::back_insert_iterator(this->Storage));
    }
  catch(vtk_utf8::invalid_code_point&)
    {
    vtkGenericWarningMacro("vtkUnicodeString::push_back(): " << character << "is not a valid Unicode code point");
    }
}

void vtkUnicodeString::append(const vtkUnicodeString& value)
{
  this->Storage.append(value.Storage);
}

void vtkUnicodeString::append(size_type count, value_type character)
{
  try
    {
    this->Storage.append(vtkUnicodeString(count, character).Storage);
    }
  catch(vtk_utf8::invalid_code_point&)
    {
    vtkGenericWarningMacro("vtkUnicodeString::append(): " << character << "is not a valid Unicode code point");
    }
}

void vtkUnicodeString::append(const_iterator first, const_iterator last)
{
#ifdef __BORLANDC__
  this->Storage.append(first.Position, last.Position - first.Position);
#else
  this->Storage.append(first.Position, last.Position);
#endif
}

void vtkUnicodeString::assign(const vtkUnicodeString& value)
{
  this->Storage.assign(value.Storage);
}

void vtkUnicodeString::assign(size_type count, value_type character)
{
  try
    {
    this->Storage.assign(vtkUnicodeString(count, character).Storage);
    }
  catch(vtk_utf8::invalid_code_point&)
    {
    vtkGenericWarningMacro("vtkUnicodeString::assign(): " << character << "is not a valid Unicode code point");
    }
}

void vtkUnicodeString::assign(const_iterator first, const_iterator last)
{
#ifdef __BORLANDC__
  this->Storage.assign(first.Position, last.Position - first.Position);
#else
  this->Storage.assign(first.Position, last.Position);
#endif
}

void vtkUnicodeString::clear()
{
  // We use erase() because MSVC 6 doesn't provide clear() ...
  this->Storage.erase(this->Storage.begin(), this->Storage.end());
}

vtkUnicodeString vtkUnicodeString::fold_case() const
{
  typedef vtkstd::map<value_type, vtkUnicodeString> map_t;

  static map_t map;
  if(map.empty())
    {
    #include <vtkUnicodeCaseFoldData.h>

    for(value_type* i = &vtkUnicodeCaseFoldData[0]; *i; ++i)
      {
      const value_type code = *i;
      vtkUnicodeString mapping;
      for(++i; *i; ++i)
        {
        mapping.push_back(*i);
        }
      map.insert(vtkstd::make_pair(code, mapping));
      }
    }

  vtkUnicodeString result;

  for(vtkUnicodeString::const_iterator source = this->begin(); source != this->end(); ++source)
    {
    map_t::const_iterator target = map.find(*source);
    if(target != map.end())
      {
      result.append(target->second);
      }
    else
      {
      result.push_back(*source);
      }
    }

  return result;
}

int vtkUnicodeString::compare(const vtkUnicodeString& rhs) const
{
  return this->Storage.compare(rhs.Storage);
}

vtkUnicodeString vtkUnicodeString::substr(size_type offset, size_type count) const
{
  vtkstd::string::const_iterator from = this->Storage.begin();
  vtkstd::string::const_iterator last = this->Storage.end();

  while(from != last && offset--)
    vtk_utf8::unchecked::advance(from, 1);

  vtkstd::string::const_iterator to = from;
  while(to != last && count--)
    vtk_utf8::unchecked::advance(to, 1);

  return vtkUnicodeString(from, to);
}

void vtkUnicodeString::swap(vtkUnicodeString& rhs)
{
  vtkstd::swap(this->Storage, rhs.Storage);
}

bool operator==(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) == 0;
}

bool operator!=(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) != 0;
}

bool operator<(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) < 0;
}

bool operator<=(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) <= 0;
}

bool operator>=(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) >= 0;
}

bool operator>(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) > 0;
}
<commit_msg>COMP: fix ifdefs to accomodate bcc58.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkUnicodeString.cxx

-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

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

#include "vtkUnicodeString.h"

#include <vtkObject.h>
#include <utf8.h>

#include <vtkstd/map>
#include <vtkstd/stdexcept>

///////////////////////////////////////////////////////////////////////////
// vtkUnicodeString::const_iterator

vtkUnicodeString::const_iterator::const_iterator()
{
}

vtkUnicodeString::const_iterator::const_iterator(vtkstd::string::const_iterator position) :
  Position(position)
{
}

vtkUnicodeString::value_type vtkUnicodeString::const_iterator::operator*() const
{
  return vtk_utf8::unchecked::peek_next(this->Position);
}

bool vtkUnicodeString::const_iterator::operator==(const const_iterator& rhs) const
{
  return this->Position == rhs.Position;
}

bool vtkUnicodeString::const_iterator::operator!=(const const_iterator& rhs) const
{
  return !(*this == rhs);
}

vtkUnicodeString::const_iterator& vtkUnicodeString::const_iterator::operator++()
{
  vtk_utf8::unchecked::next(this->Position);
  return *this;
}

vtkUnicodeString::const_iterator vtkUnicodeString::const_iterator::operator++(int)
{
  const_iterator result(this->Position);
  vtk_utf8::unchecked::next(this->Position);
  return result;
}

vtkUnicodeString::const_iterator& vtkUnicodeString::const_iterator::operator--()
{
  vtk_utf8::unchecked::prior(this->Position);
  return *this;
}

vtkUnicodeString::const_iterator vtkUnicodeString::const_iterator::operator--(int)
{
  const_iterator result(this->Position);
  vtk_utf8::unchecked::prior(this->Position);
  return result;
}

///////////////////////////////////////////////////////////////////////////
// vtkUnicodeString::back_insert_iterator

// We provide our own implementation of vtkstd::back_insert_iterator for
// use with MSVC 6, where push_back() isn't implemented for vtkstd::string.

class vtkUnicodeString::back_insert_iterator
{
public:
  back_insert_iterator(vtkstd::string& container) :
    Container(&container)
  {
  }

  back_insert_iterator& operator*()
  {
    return *this;
  }

  back_insert_iterator& operator++()
  {
    return *this;
  }

  back_insert_iterator& operator++(int)
  {
    return *this;
  }

  back_insert_iterator& operator=(vtkstd::string::const_reference value)
  {
#if defined(_MSC_VER) && (_MSC_VER < 1300) // MSVC 6
    this->Container->append(1, value);
#else
    this->Container->push_back(value);
#endif
    return *this;
  }

private:
  vtkstd::string* Container;
};

///////////////////////////////////////////////////////////////////////////
// vtkUnicodeString

vtkUnicodeString::vtkUnicodeString()
{
}

vtkUnicodeString::vtkUnicodeString(const vtkUnicodeString& rhs) :
  Storage(rhs.Storage)
{
}

vtkUnicodeString::vtkUnicodeString(size_type count, value_type character)
{
  for(size_type i = 0; i != count; ++i)
    vtk_utf8::append(character, vtkUnicodeString::back_insert_iterator(this->Storage));
}

vtkUnicodeString::vtkUnicodeString(const_iterator first, const_iterator last) :
  Storage(first.Position, last.Position)
{
}

bool vtkUnicodeString::is_utf8(const char* value)
{
  return vtkUnicodeString::is_utf8(vtkstd::string(value ? value : ""));
}

bool vtkUnicodeString::is_utf8(const vtkstd::string& value)
{
  return vtk_utf8::is_valid(value.begin(), value.end());
}

vtkUnicodeString vtkUnicodeString::from_utf8(const char* value)
{
  return vtkUnicodeString::from_utf8(vtkstd::string(value ? value : ""));
}

vtkUnicodeString vtkUnicodeString::from_utf8(const char* begin, const char* end)
{
  vtkUnicodeString result;
  if(vtk_utf8::is_valid(begin, end))
    {
    result.Storage = vtkstd::string(begin, end);
    }
  else
    {
    vtkGenericWarningMacro("vtkUnicodeString::from_utf8(): not a valid UTF-8 string.");
    }
  return result;
}

vtkUnicodeString vtkUnicodeString::from_utf8(const vtkstd::string& value)
{
  vtkUnicodeString result;
  if(vtk_utf8::is_valid(value.begin(), value.end()))
    {
    result.Storage = value;
    }
  else
    {
    vtkGenericWarningMacro("vtkUnicodeString::from_utf8(): not a valid UTF-8 string.");
    }
  return result;
}

vtkUnicodeString vtkUnicodeString::from_utf16(const vtkTypeUInt16* value)
{
  vtkUnicodeString result;

  if(value)
    {
    size_type length = 0;
    while(value[length])
      ++length;

    try
      {
      vtk_utf8::utf16to8(value, value + length, vtkUnicodeString::back_insert_iterator(result.Storage));
      }
    catch(vtk_utf8::invalid_utf16&)
      {
      vtkGenericWarningMacro(<< "vtkUnicodeString::from_utf16(): not a valid UTF-16 string.");
      }
    }

  return result;
}

vtkUnicodeString& vtkUnicodeString::operator=(const vtkUnicodeString& rhs)
{
  if(this == &rhs)
    return *this;

  this->Storage = rhs.Storage;
  return *this;
}

vtkUnicodeString::const_iterator vtkUnicodeString::begin() const
{
  return const_iterator(this->Storage.begin());
}

vtkUnicodeString::const_iterator vtkUnicodeString::end() const
{
  return const_iterator(this->Storage.end());
}

vtkUnicodeString::value_type vtkUnicodeString::at(size_type offset) const
{
  if(offset >= this->character_count())
    throw vtkstd::out_of_range("character out-of-range");

  vtkstd::string::const_iterator iterator = this->Storage.begin();
  vtk_utf8::unchecked::advance(iterator, offset);
  return vtk_utf8::unchecked::peek_next(iterator);
}

vtkUnicodeString::value_type vtkUnicodeString::operator[](size_type offset) const
{
  vtkstd::string::const_iterator iterator = this->Storage.begin();
  vtk_utf8::unchecked::advance(iterator, offset);
  return vtk_utf8::unchecked::peek_next(iterator);
}

const char* vtkUnicodeString::utf8_str() const
{
  return this->Storage.c_str();
}

void vtkUnicodeString::utf8_str(vtkstd::string& result) const
{
  result = this->Storage;
}

vtkstd::vector<vtkTypeUInt16> vtkUnicodeString::utf16_str() const
{
  vtkstd::vector<vtkTypeUInt16> result;
  vtk_utf8::unchecked::utf8to16(this->Storage.begin(), this->Storage.end(), vtkstd::back_inserter(result));
  return result;
}

void vtkUnicodeString::utf16_str(vtkstd::vector<vtkTypeUInt16>& result) const
{
  result.clear();
  vtk_utf8::unchecked::utf8to16(this->Storage.begin(), this->Storage.end(), vtkstd::back_inserter(result));
}

vtkUnicodeString::size_type vtkUnicodeString::byte_count() const
{
  return this->Storage.size();
}

vtkUnicodeString::size_type vtkUnicodeString::character_count() const
{
  return vtk_utf8::unchecked::distance(this->Storage.begin(), this->Storage.end());
}

bool vtkUnicodeString::empty() const
{
  return this->Storage.empty();
}

const vtkUnicodeString::size_type vtkUnicodeString::npos = vtkstd::string::npos;

vtkUnicodeString& vtkUnicodeString::operator+=(value_type value)
{
  this->push_back(value);
  return *this;
}

vtkUnicodeString& vtkUnicodeString::operator+=(const vtkUnicodeString& rhs)
{
  this->append(rhs);
  return *this;
}

void vtkUnicodeString::push_back(value_type character)
{
  try
    {
    vtk_utf8::append(character, vtkUnicodeString::back_insert_iterator(this->Storage));
    }
  catch(vtk_utf8::invalid_code_point&)
    {
    vtkGenericWarningMacro("vtkUnicodeString::push_back(): " << character << "is not a valid Unicode code point");
    }
}

void vtkUnicodeString::append(const vtkUnicodeString& value)
{
  this->Storage.append(value.Storage);
}

void vtkUnicodeString::append(size_type count, value_type character)
{
  try
    {
    this->Storage.append(vtkUnicodeString(count, character).Storage);
    }
  catch(vtk_utf8::invalid_code_point&)
    {
    vtkGenericWarningMacro("vtkUnicodeString::append(): " << character << "is not a valid Unicode code point");
    }
}

void vtkUnicodeString::append(const_iterator first, const_iterator last)
{
#if defined (__BORLANDC__) && (__BORLANDC__ < 0x0580)
  this->Storage.append(first.Position, last.Position - first.Position);
#else
  this->Storage.append(first.Position, last.Position);
#endif
}

void vtkUnicodeString::assign(const vtkUnicodeString& value)
{
  this->Storage.assign(value.Storage);
}

void vtkUnicodeString::assign(size_type count, value_type character)
{
  try
    {
    this->Storage.assign(vtkUnicodeString(count, character).Storage);
    }
  catch(vtk_utf8::invalid_code_point&)
    {
    vtkGenericWarningMacro("vtkUnicodeString::assign(): " << character << "is not a valid Unicode code point");
    }
}

void vtkUnicodeString::assign(const_iterator first, const_iterator last)
{
#if defined (__BORLANDC__) && (__BORLANDC__ < 0x0580)
  this->Storage.assign(first.Position, last.Position - first.Position);
#else
  this->Storage.assign(first.Position, last.Position);
#endif
}

void vtkUnicodeString::clear()
{
  // We use erase() because MSVC 6 doesn't provide clear() ...
  this->Storage.erase(this->Storage.begin(), this->Storage.end());
}

vtkUnicodeString vtkUnicodeString::fold_case() const
{
  typedef vtkstd::map<value_type, vtkUnicodeString> map_t;

  static map_t map;
  if(map.empty())
    {
    #include <vtkUnicodeCaseFoldData.h>

    for(value_type* i = &vtkUnicodeCaseFoldData[0]; *i; ++i)
      {
      const value_type code = *i;
      vtkUnicodeString mapping;
      for(++i; *i; ++i)
        {
        mapping.push_back(*i);
        }
      map.insert(vtkstd::make_pair(code, mapping));
      }
    }

  vtkUnicodeString result;

  for(vtkUnicodeString::const_iterator source = this->begin(); source != this->end(); ++source)
    {
    map_t::const_iterator target = map.find(*source);
    if(target != map.end())
      {
      result.append(target->second);
      }
    else
      {
      result.push_back(*source);
      }
    }

  return result;
}

int vtkUnicodeString::compare(const vtkUnicodeString& rhs) const
{
  return this->Storage.compare(rhs.Storage);
}

vtkUnicodeString vtkUnicodeString::substr(size_type offset, size_type count) const
{
  vtkstd::string::const_iterator from = this->Storage.begin();
  vtkstd::string::const_iterator last = this->Storage.end();

  while(from != last && offset--)
    vtk_utf8::unchecked::advance(from, 1);

  vtkstd::string::const_iterator to = from;
  while(to != last && count--)
    vtk_utf8::unchecked::advance(to, 1);

  return vtkUnicodeString(from, to);
}

void vtkUnicodeString::swap(vtkUnicodeString& rhs)
{
  vtkstd::swap(this->Storage, rhs.Storage);
}

bool operator==(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) == 0;
}

bool operator!=(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) != 0;
}

bool operator<(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) < 0;
}

bool operator<=(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) <= 0;
}

bool operator>=(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) >= 0;
}

bool operator>(const vtkUnicodeString& lhs, const vtkUnicodeString& rhs)
{
  return lhs.compare(rhs) > 0;
}
<|endoftext|>


<commit_before>#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>

using namespace std;
using namespace cv;

static void help()
{
    cout << "\n This program demonstrates how to detect compute and match ORB BRISK and AKAZE descriptors \n"
        "Usage: \n"
        "  ./matchmethod_orb_akaze_brisk <image1(../data/basketball1.png as default)> <image2(../data/basketball2.png as default)>\n"
        "Press a key when image window is active to change algorithm or descriptor";
}

int main(int argc, char *argv[])
{
    vector<String> typeDesc;
    vector<String> typeAlgoMatch;
    vector<String> fileName;
    help();
    // This descriptor are going to be detect and compute
    typeDesc.push_back("AKAZE-DESCRIPTOR_KAZE_UPRIGHT");    // see http://docs.opencv.org/trunk/d8/d30/classcv_1_1AKAZE.html
    typeDesc.push_back("AKAZE");    // see http://docs.opencv.org/trunk/d8/d30/classcv_1_1AKAZE.html
    typeDesc.push_back("ORB");      // see http://docs.opencv.org/trunk/de/dbf/classcv_1_1BRISK.html
    typeDesc.push_back("BRISK");    // see http://docs.opencv.org/trunk/db/d95/classcv_1_1ORB.html
   // This algorithm would be used to match descriptors see http://docs.opencv.org/trunk/db/d39/classcv_1_1DescriptorMatcher.html#ab5dc5036569ecc8d47565007fa518257
    typeAlgoMatch.push_back("BruteForce");
    typeAlgoMatch.push_back("BruteForce-L1");
    typeAlgoMatch.push_back("BruteForce-Hamming");
    typeAlgoMatch.push_back("BruteForce-Hamming(2)");
    if (argc==1)
    {
        fileName.push_back("../data/basketball1.png");
        fileName.push_back("../data/basketball2.png");
    }
    else if (argc==3)
    {
        fileName.push_back(argv[1]);
        fileName.push_back(argv[2]);
    }
    else
    {
        help();
        return(0);
    }
    Mat img1 = imread(fileName[0], IMREAD_GRAYSCALE);
    Mat img2 = imread(fileName[1], IMREAD_GRAYSCALE);
    if (img1.rows*img1.cols <= 0)
        {
        cout << "Image " << fileName[0] << " is empty or cannot be found\n";
        return(0);
        }
    if (img2.rows*img2.cols <= 0)
        {
        cout << "Image " << fileName[1] << " is empty or cannot be found\n";
        return(0);
        }

    vector<double> desMethCmp;
    Ptr<Feature2D> b;

    // Descriptor loop
    vector<String>::iterator itDesc;
    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
    {
        Ptr<DescriptorMatcher> descriptorMatcher;
        // Match between img1 and img2
        vector<DMatch> matches;
        // keypoint  for img1 and img2
        vector<KeyPoint> keyImg1, keyImg2;
        // Descriptor for img1 and img2
        Mat descImg1, descImg2;
        vector<String>::iterator itMatcher = typeAlgoMatch.end();
        if (*itDesc == "AKAZE-DESCRIPTOR_KAZE_UPRIGHT"){
            b = AKAZE::create(AKAZE::DESCRIPTOR_KAZE_UPRIGHT);
            }
        if (*itDesc == "AKAZE"){
            b = AKAZE::create();
            }
        if (*itDesc == "ORB"){
            b = ORB::create();
        }
        else if (*itDesc == "BRISK"){
            b = BRISK::create();
        }
        try {
            // We can detect keypoint with detect method
            b->detect(img1, keyImg1, Mat());
            // and compute their descriptors with method  compute
            b->compute(img1, keyImg1, descImg1);
            // or detect and compute descriptors in one step
            b->detectAndCompute(img2, Mat(),keyImg2, descImg2,false);
            // Match method loop
            for (itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++){
                descriptorMatcher = DescriptorMatcher::create(*itMatcher);
                if ((*itMatcher == "BruteForce-Hamming" || *itMatcher == "BruteForce-Hamming(2)") && (b->descriptorType() == CV_32F || b->defaultNorm() <= NORM_L2SQR) )
                {
                    cout << "**************************************************************************\n";
                    cout << "It's strange. You should use Hamming distance only for a binary descriptor\n";
                    cout << "**************************************************************************\n";
                }
                try
                {
                    descriptorMatcher->match(descImg1, descImg2, matches, Mat());
                    // Keep best matches only to have a nice drawing.
                    // We sort distance between descriptor matches
                    Mat index;
                    int nbMatch=int(matches.size());
                    Mat tab(nbMatch, 1, CV_32F);
                    for (int i = 0; i<nbMatch; i++)
                    {
                        tab.at<float>(i, 0) = matches[i].distance;
                    }
                    sortIdx(tab, index, SORT_EVERY_COLUMN + SORT_ASCENDING);
                    vector<DMatch> bestMatches;
                    for (int i = 0; i<30; i++)
                    {
                        bestMatches.push_back(matches[index.at<int>(i, 0)]);
                    }
                    Mat result;
                    drawMatches(img1, keyImg1, img2, keyImg2, bestMatches, result);
                    namedWindow(*itDesc+": "+*itMatcher, WINDOW_AUTOSIZE);
                    imshow(*itDesc + ": " + *itMatcher, result);
                    // Saved result could be wrong due to bug 4308
                    FileStorage fs(*itDesc + "_" + *itMatcher + ".yml", FileStorage::WRITE);
                    fs<<"Matches"<<matches;
                    vector<DMatch>::iterator it;
                    cout<<"**********Match results**********\n";
                    cout << "Index \tIndex \tdistance\n";
                    cout << "in img1\tin img2\n";
                    // Use to compute distance between keyPoint matches and to evaluate match algorithm
                    double cumSumDist2=0;
                    for (it = bestMatches.begin(); it != bestMatches.end(); it++)
                    {
                        cout << it->queryIdx << "\t" <<  it->trainIdx << "\t"  <<  it->distance << "\n";
                        Point2d p=keyImg1[it->queryIdx].pt-keyImg2[it->trainIdx].pt;
                        cumSumDist2=p.x*p.x+p.y*p.y;
                    }
                    desMethCmp.push_back(cumSumDist2);
                    waitKey();
                }
                catch (Exception& e)
                    {
                    desMethCmp.push_back(-1);
                    }
                }
        }
        catch (Exception& e)
        {
            cout << "Feature : " << *itDesc << "\n";
            if (itMatcher != typeAlgoMatch.end())
            {
                cout << "Matcher : " << *itMatcher << "\n";
            }
            cout << e.msg << endl;
        }
    }
    int i=0;
    cout << "Cumulative distance between keypoint match for different algorithm and feature detector \n\t";
    cout << "We cannot say which is the best but we can say results are differents! \n\t";
    for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++)
    {
        cout<<*itMatcher<<"\t";
    }
    cout << "\n";
    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
    {
        cout << *itDesc << "\t";
        for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++, i++)
        {
            cout << desMethCmp[i]<<"\t";
        }
        cout<<"\n";
    }
    return 0;
}
<commit_msg>trailing whitespace<commit_after>#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>

using namespace std;
using namespace cv;

static void help()
{
    cout << "\n This program demonstrates how to detect compute and match ORB BRISK and AKAZE descriptors \n"
        "Usage: \n"
        "  ./matchmethod_orb_akaze_brisk <image1(../data/basketball1.png as default)> <image2(../data/basketball2.png as default)>\n"
        "Press a key when image window is active to change algorithm or descriptor";
}

int main(int argc, char *argv[])
{
    vector<String> typeDesc;
    vector<String> typeAlgoMatch;
    vector<String> fileName;
    help();
    // This descriptor are going to be detect and compute
    typeDesc.push_back("AKAZE-DESCRIPTOR_KAZE_UPRIGHT");    // see http://docs.opencv.org/trunk/d8/d30/classcv_1_1AKAZE.html
    typeDesc.push_back("AKAZE");    // see http://docs.opencv.org/trunk/d8/d30/classcv_1_1AKAZE.html
    typeDesc.push_back("ORB");      // see http://docs.opencv.org/trunk/de/dbf/classcv_1_1BRISK.html
    typeDesc.push_back("BRISK");    // see http://docs.opencv.org/trunk/db/d95/classcv_1_1ORB.html
   // This algorithm would be used to match descriptors see http://docs.opencv.org/trunk/db/d39/classcv_1_1DescriptorMatcher.html#ab5dc5036569ecc8d47565007fa518257
    typeAlgoMatch.push_back("BruteForce");
    typeAlgoMatch.push_back("BruteForce-L1");
    typeAlgoMatch.push_back("BruteForce-Hamming");
    typeAlgoMatch.push_back("BruteForce-Hamming(2)");
    if (argc==1)
    {
        fileName.push_back("../data/basketball1.png");
        fileName.push_back("../data/basketball2.png");
    }
    else if (argc==3)
    {
        fileName.push_back(argv[1]);
        fileName.push_back(argv[2]);
    }
    else
    {
        help();
        return(0);
    }
    Mat img1 = imread(fileName[0], IMREAD_GRAYSCALE);
    Mat img2 = imread(fileName[1], IMREAD_GRAYSCALE);
    if (img1.rows*img1.cols <= 0)
        {
        cout << "Image " << fileName[0] << " is empty or cannot be found\n";
        return(0);
        }
    if (img2.rows*img2.cols <= 0)
        {
        cout << "Image " << fileName[1] << " is empty or cannot be found\n";
        return(0);
        }

    vector<double> desMethCmp;
    Ptr<Feature2D> b;

    // Descriptor loop
    vector<String>::iterator itDesc;
    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
    {
        Ptr<DescriptorMatcher> descriptorMatcher;
        // Match between img1 and img2
        vector<DMatch> matches;
        // keypoint  for img1 and img2
        vector<KeyPoint> keyImg1, keyImg2;
        // Descriptor for img1 and img2
        Mat descImg1, descImg2;
        vector<String>::iterator itMatcher = typeAlgoMatch.end();
        if (*itDesc == "AKAZE-DESCRIPTOR_KAZE_UPRIGHT"){
            b = AKAZE::create(AKAZE::DESCRIPTOR_KAZE_UPRIGHT);
            }
        if (*itDesc == "AKAZE"){
            b = AKAZE::create();
            }
        if (*itDesc == "ORB"){
            b = ORB::create();
        }
        else if (*itDesc == "BRISK"){
            b = BRISK::create();
        }
        try {
            // We can detect keypoint with detect method
            b->detect(img1, keyImg1, Mat());
            // and compute their descriptors with method  compute
            b->compute(img1, keyImg1, descImg1);
            // or detect and compute descriptors in one step
            b->detectAndCompute(img2, Mat(),keyImg2, descImg2,false);
            // Match method loop
            for (itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++){
                descriptorMatcher = DescriptorMatcher::create(*itMatcher);
                if ((*itMatcher == "BruteForce-Hamming" || *itMatcher == "BruteForce-Hamming(2)") && (b->descriptorType() == CV_32F || b->defaultNorm() <= NORM_L2SQR) )
                {
                    cout << "**************************************************************************\n";
                    cout << "It's strange. You should use Hamming distance only for a binary descriptor\n";
                    cout << "**************************************************************************\n";
                }
                try
                {
                    descriptorMatcher->match(descImg1, descImg2, matches, Mat());
                    // Keep best matches only to have a nice drawing.
                    // We sort distance between descriptor matches
                    Mat index;
                    int nbMatch=int(matches.size());
                    Mat tab(nbMatch, 1, CV_32F);
                    for (int i = 0; i<nbMatch; i++)
                    {
                        tab.at<float>(i, 0) = matches[i].distance;
                    }
                    sortIdx(tab, index, SORT_EVERY_COLUMN + SORT_ASCENDING);
                    vector<DMatch> bestMatches;
                    for (int i = 0; i<30; i++)
                    {
                        bestMatches.push_back(matches[index.at<int>(i, 0)]);
                    }
                    Mat result;
                    drawMatches(img1, keyImg1, img2, keyImg2, bestMatches, result);
                    namedWindow(*itDesc+": "+*itMatcher, WINDOW_AUTOSIZE);
                    imshow(*itDesc + ": " + *itMatcher, result);
                    // Saved result could be wrong due to bug 4308
                    FileStorage fs(*itDesc + "_" + *itMatcher + ".yml", FileStorage::WRITE);
                    fs<<"Matches"<<matches;
                    vector<DMatch>::iterator it;
                    cout<<"**********Match results**********\n";
                    cout << "Index \tIndex \tdistance\n";
                    cout << "in img1\tin img2\n";
                    // Use to compute distance between keyPoint matches and to evaluate match algorithm
                    double cumSumDist2=0;
                    for (it = bestMatches.begin(); it != bestMatches.end(); it++)
                    {
                        cout << it->queryIdx << "\t" <<  it->trainIdx << "\t"  <<  it->distance << "\n";
                        Point2d p=keyImg1[it->queryIdx].pt-keyImg2[it->trainIdx].pt;
                        cumSumDist2=p.x*p.x+p.y*p.y;
                    }
                    desMethCmp.push_back(cumSumDist2);
                    waitKey();
                }
                catch (Exception& e)
                    {
                    desMethCmp.push_back(-1);
                    }
                }
        }
        catch (Exception& e)
        {
            cout << "Feature : " << *itDesc << "\n";
            if (itMatcher != typeAlgoMatch.end())
            {
                cout << "Matcher : " << *itMatcher << "\n";
            }
            cout << e.msg << endl;
        }
    }
    int i=0;
    cout << "Cumulative distance between keypoint match for different algorithm and feature detector \n\t";
    cout << "We cannot say which is the best but we can say results are differents! \n\t";
    for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++)
    {
        cout<<*itMatcher<<"\t";
    }
    cout << "\n";
    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
    {
        cout << *itDesc << "\t";
        for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++, i++)
        {
            cout << desMethCmp[i]<<"\t";
        }
        cout<<"\n";
    }
    return 0;
}
<|endoftext|>


<commit_before>///
/// @file  generate.hpp
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef GENERATE_HPP
#define GENERATE_HPP

#include <primesieve.hpp>

#include <stdint.h>
#include <vector>

namespace primesum {

/// Generate a vector with the primes <= max.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
///
template <typename T>
std::vector<T> generate_primes(int64_t max)
{
  std::vector<T> primes;
  primes.push_back(0);
  primesieve::generate_primes(max, &primes);
  return primes;
}

/// Generate a vector with the prime sums <= max.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
///
template <typename T>
std::vector<T> generate_prime_sums(int64_t max)
{
  std::vector<T> primes;
  primes.push_back(0);
  primesieve::generate_primes(max, &primes);

  for (uint64_t i = 1; i < primes.size(); i++)
    primes[i] += primes[i - 1];

  return primes;
}

/// Generate a vector with the primes <= max.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
//
std::vector<int32_t> generate_primes(int64_t max);

/// Generate a vector with the first n primes.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
//
std::vector<int32_t> generate_n_primes(int64_t n);

/// Generate a vector with Möbius function values.
std::vector<int32_t> generate_moebius(int64_t max);

/// Generate a vector with the least prime
/// factors of the integers <= max.
///
std::vector<int32_t> generate_least_prime_factors(int64_t max);

/// Generate a vector with the prime counts below max
/// using the sieve of Eratosthenes.
///
std::vector<int32_t> generate_pi(int64_t max);

} // namespace

#endif
<commit_msg>Refactor using C++11<commit_after>///
/// @file  generate.hpp
///
/// Copyright (C) 2018 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef GENERATE_HPP
#define GENERATE_HPP

#include <primesieve.hpp>

#include <stdint.h>
#include <vector>

namespace primesum {

/// Generate a vector with the primes <= max.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
///
template <typename T>
std::vector<T> generate_primes(int64_t max)
{
  std::vector<T> primes = { 0 };
  primesieve::generate_primes(max, &primes);
  return primes;
}

/// Generate a vector with the prime sums <= max.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
///
template <typename T>
std::vector<T> generate_prime_sums(int64_t max)
{
  std::vector<T> primes = { 0 };
  primesieve::generate_primes(max, &primes);

  for (uint64_t i = 1; i < primes.size(); i++)
    primes[i] += primes[i - 1];

  return primes;
}

/// Generate a vector with the primes <= max.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
//
std::vector<int32_t> generate_primes(int64_t max);

/// Generate a vector with the first n primes.
/// The primes vector uses 1-indexing i.e. primes[1] = 2.
//
std::vector<int32_t> generate_n_primes(int64_t n);

/// Generate a vector with Möbius function values.
std::vector<int32_t> generate_moebius(int64_t max);

/// Generate a vector with the least prime
/// factors of the integers <= max.
///
std::vector<int32_t> generate_least_prime_factors(int64_t max);

/// Generate a vector with the prime counts below max
/// using the sieve of Eratosthenes.
///
std::vector<int32_t> generate_pi(int64_t max);

} // namespace

#endif
<|endoftext|>


<commit_before>#include "TileCollideableGroup.hpp"
#include "Tilemap.hpp"
#include "comp/TileCollisionComponent.hpp"
#include "Logfile.hpp"
#include <unordered_set>
#include <array>
#include <algorithm>

TileCollideableGroup::TileCollideableGroup(jd::Tilemap& tilemap):
    m_tilemap(tilemap)
{
}

void TileCollideableGroup::setProxy(unsigned tileId, TileCollisionComponent* proxy)
{
    if (!m_proxyEntities.insert(std::make_pair(tileId, proxy)).second)
        throw std::logic_error(
            __FUNCTION__ ": cannot assign proxy entity: already assigned");
}

void TileCollideableGroup::setColliding(Vector3u pos, TileCollisionComponent* e)
{
    auto const it = m_entities.find(pos);
    bool const found = it != m_entities.end();
    if (e) {
        if (found) {
            it->second->notifyOverride(pos, *e);
            it->second = e;
        } else {
            bool const success = m_entities.insert(std::make_pair(pos, e)).second;
            assert(success);
        }
    } else if (found) {
        m_entities.erase(pos);
    } else {
        LOG_W("Attempt to unregister a TileCollisionComponent which was not registered.");
    }
}

void TileCollideableGroup::addCollisions(
    Vector3u pos, std::vector<Collision>& result,
    Entity* e, sf::FloatRect const& r)
{
    auto const iEntity = m_entities.find(pos);
    if (iEntity != m_entities.end()) {
        if (e)
            iEntity->second->notifyCollision(pos, *e, r);
        result.push_back(Collision(
            iEntity->second->parent(),
            m_tilemap.globalTileRect(sf::Vector2i(pos.x, pos.y))));
    } else {
        unsigned const tileId = m_tilemap[pos];
        auto const iProxy = m_proxyEntities.find(tileId);
        if (iProxy != m_proxyEntities.end()) {
            if (e)
                iProxy->second->notifyCollision(pos, *e, r);
            result.push_back(Collision(
                iProxy->second->parent(),
                m_tilemap.globalTileRect(sf::Vector2i(pos.x, pos.y))));
        }
    } // if no entity at pos registered
}

std::vector<Collision> TileCollideableGroup::colliding(sf::FloatRect const& r, Entity* e)
{
    sf::Vector2u begin = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(jd::topLeft(r)));
    begin.x = std::max(begin.x, 0u);
    begin.y = std::max(begin.y, 0u);
    sf::Vector2u last = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(jd::bottomRight(r)));
    last.x = std::min(last.x, m_tilemap.size().x - 1);
    last.y = std::min(last.y, m_tilemap.size().y - 1);

    std::vector<Collision> result;
    result.reserve((last.x - begin.x + 1) * (last.y - begin.y + 1));

    for (unsigned z = 0; z < m_tilemap.size().z; ++z) {
        for (unsigned x = begin.x; x <= last.x; ++x) {
            for (unsigned y = begin.y; y <= last.y; ++y) {
                Vector3u const pos(x, y, z);
                addCollisions(pos, result, e, r);
            } // for y
        } // for x
    } // for z
    return result;
}

namespace {
    std::array<sf::Vector2i, 8> surroundingTiles(sf::Vector2i p)
    {
        std::array<sf::Vector2i, 8> result;
        std::fill(result.begin(), result.end(), p);

        // 012
        // 3p4
        // 567
        --result[0].x; --result[0].y;
                       --result[1].y;
        ++result[2].x; --result[2].y;
        --result[3].x;
        ++result[4].x;
        --result[5].x; ++result[5].y;
                       ++result[6].y;
        ++result[7].x; ++result[7].y;

        return result;
    }
}

std::vector<Collision> TileCollideableGroup::colliding(sf::Vector2f gp1, sf::Vector2f gp2)
{
    sf::Vector2u p1 = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(gp1));
    sf::Vector2u p2 = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(gp2));

    std::vector<Collision> result;

    if (!jd::clipLine(p1, p2, sf::Rect<unsigned>(
        0, 0, m_tilemap.size().x, m_tilemap.size().y)))
        return result;

    sf::Vector2u const d = p2 - p1;

    result.reserve(static_cast<std::size_t>(
        jd::math::abs(static_cast<sf::Vector2f>(d))));

    sf::Vector2u pos = p1;
    sf::Vector2u lastPos = pos;
    bool foundNext = false;
    do {
        Vector3u idx(pos.x, pos.y, 0);
        for (; idx.z < m_tilemap.size().z; ++idx.z)
            addCollisions(idx, result);

        auto const surrounding(surroundingTiles(
            static_cast<sf::Vector2i>(pos)));
        for (sf::Vector2i next : surrounding) {
            if (pos != lastPos &&
                m_tilemap.isValidPosition(jd::vec2to3(next, 0)) &&
                jd::intersection(
                    p1, p2,
                    sf::Rect<unsigned>(
                        static_cast<sf::Vector2u>(next),
                        sf::Vector2u(1, 1)))
            ) {
                lastPos = pos;
                pos = static_cast<sf::Vector2u>(next);
                foundNext = true;
                break;
            }
        }
        assert(foundNext);
    } while (pos != p2);
    return result;
}
<commit_msg>TileCollideableGroup::setProxy: Remove proxy if nullptr is passed.<commit_after>#include "TileCollideableGroup.hpp"
#include "Tilemap.hpp"
#include "comp/TileCollisionComponent.hpp"
#include "Logfile.hpp"
#include <unordered_set>
#include <array>
#include <algorithm>

TileCollideableGroup::TileCollideableGroup(jd::Tilemap& tilemap):
    m_tilemap(tilemap)
{
}

void TileCollideableGroup::setProxy(unsigned tileId, TileCollisionComponent* proxy)
{
    if (!proxy) {
        std::size_t const erasedCount = m_proxyEntities.erase(tileId);
        assert(erasedCount < 2);
        if (!erasedCount)
            LOG_W("Attempt to unset a proxy, which was not set.");
    } else if (!m_proxyEntities.insert(std::make_pair(tileId, proxy)).second)
        throw std::logic_error(
            __FUNCTION__ ": cannot assign proxy entity: already assigned");
}

void TileCollideableGroup::setColliding(Vector3u pos, TileCollisionComponent* e)
{
    auto const it = m_entities.find(pos);
    bool const found = it != m_entities.end();
    if (e) {
        if (found) {
            it->second->notifyOverride(pos, *e);
            it->second = e;
        } else {
            bool const success = m_entities.insert(std::make_pair(pos, e)).second;
            assert(success);
        }
    } else if (found) {
        m_entities.erase(pos);
    } else {
        LOG_W("Attempt to unregister a TileCollisionComponent which was not registered.");
    }
}

void TileCollideableGroup::addCollisions(
    Vector3u pos, std::vector<Collision>& result,
    Entity* e, sf::FloatRect const& r)
{
    auto const iEntity = m_entities.find(pos);
    if (iEntity != m_entities.end()) {
        if (e)
            iEntity->second->notifyCollision(pos, *e, r);
        result.push_back(Collision(
            iEntity->second->parent(),
            m_tilemap.globalTileRect(sf::Vector2i(pos.x, pos.y))));
    } else {
        unsigned const tileId = m_tilemap[pos];
        auto const iProxy = m_proxyEntities.find(tileId);
        if (iProxy != m_proxyEntities.end()) {
            if (e)
                iProxy->second->notifyCollision(pos, *e, r);
            result.push_back(Collision(
                iProxy->second->parent(),
                m_tilemap.globalTileRect(sf::Vector2i(pos.x, pos.y))));
        }
    } // if no entity at pos registered
}

std::vector<Collision> TileCollideableGroup::colliding(sf::FloatRect const& r, Entity* e)
{
    sf::Vector2u begin = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(jd::topLeft(r)));
    begin.x = std::max(begin.x, 0u);
    begin.y = std::max(begin.y, 0u);
    sf::Vector2u last = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(jd::bottomRight(r)));
    last.x = std::min(last.x, m_tilemap.size().x - 1);
    last.y = std::min(last.y, m_tilemap.size().y - 1);

    std::vector<Collision> result;
    result.reserve((last.x - begin.x + 1) * (last.y - begin.y + 1));

    for (unsigned z = 0; z < m_tilemap.size().z; ++z) {
        for (unsigned x = begin.x; x <= last.x; ++x) {
            for (unsigned y = begin.y; y <= last.y; ++y) {
                Vector3u const pos(x, y, z);
                addCollisions(pos, result, e, r);
            } // for y
        } // for x
    } // for z
    return result;
}

namespace {
    std::array<sf::Vector2i, 8> surroundingTiles(sf::Vector2i p)
    {
        std::array<sf::Vector2i, 8> result;
        std::fill(result.begin(), result.end(), p);

        // 012
        // 3p4
        // 567
        --result[0].x; --result[0].y;
                       --result[1].y;
        ++result[2].x; --result[2].y;
        --result[3].x;
        ++result[4].x;
        --result[5].x; ++result[5].y;
                       ++result[6].y;
        ++result[7].x; ++result[7].y;

        return result;
    }
}

std::vector<Collision> TileCollideableGroup::colliding(sf::Vector2f gp1, sf::Vector2f gp2)
{
    sf::Vector2u p1 = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(gp1));
    sf::Vector2u p2 = static_cast<sf::Vector2u>(
        m_tilemap.tilePosFromGlobal(gp2));

    std::vector<Collision> result;

    if (!jd::clipLine(p1, p2, sf::Rect<unsigned>(
        0, 0, m_tilemap.size().x, m_tilemap.size().y)))
        return result;

    sf::Vector2u const d = p2 - p1;

    result.reserve(static_cast<std::size_t>(
        jd::math::abs(static_cast<sf::Vector2f>(d))));

    sf::Vector2u pos = p1;
    sf::Vector2u lastPos = pos;
    bool foundNext = false;
    do {
        Vector3u idx(pos.x, pos.y, 0);
        for (; idx.z < m_tilemap.size().z; ++idx.z)
            addCollisions(idx, result);

        auto const surrounding(surroundingTiles(
            static_cast<sf::Vector2i>(pos)));
        for (sf::Vector2i next : surrounding) {
            if (pos != lastPos &&
                m_tilemap.isValidPosition(jd::vec2to3(next, 0)) &&
                jd::intersection(
                    p1, p2,
                    sf::Rect<unsigned>(
                        static_cast<sf::Vector2u>(next),
                        sf::Vector2u(1, 1)))
            ) {
                lastPos = pos;
                pos = static_cast<sf::Vector2u>(next);
                foundNext = true;
                break;
            }
        }
        assert(foundNext);
    } while (pos != p2);
    return result;
}
<|endoftext|>


<commit_before>

#include <base/configreader.hpp>
#include "instance.hpp"
#include "manager.hpp"
#include "broker.hpp"
#include "logger.hpp"
#include <string>
#include <iostream>

using namespace std;

namespace cossb {
namespace core {

bool cossb_init(const char* manifest)
{

	//1. load manifest file
	if(!cossb_config->load(manifest))
		return false;

	//2. create(setup) instances according to the manifest
	if(!cossb_system_manager->setup(cossb_config))
		return false;

	return true;
}

void cossb_destroy()
{
	cossb_stop();
	cossb_log->log(log::loglevel::INFO, "Now terminating...");
	cossb_system_manager->destroy();
	cossb_config->destroy();
}

bool cossb_sync()
{
	return true;
}

bool cossb_start()
{
	cossb_log->log(log::loglevel::INFO, "Now all components is running...");
	if(cossb_component_manager->run())
		return true;

	return false;
}

bool cossb_stop()
{
	cossb_log->log(log::loglevel::INFO, "Now all components is stopping...");
	if(cossb_component_manager->stop())
		return true;

	return false;
}

} /* namespace core */
} /* namespace cossb */
<commit_msg>cossb_stop function checks the size of container.<commit_after>

#include <base/configreader.hpp>
#include "instance.hpp"
#include "manager.hpp"
#include "broker.hpp"
#include "logger.hpp"
#include <string>
#include <iostream>

using namespace std;

namespace cossb {
namespace core {

bool cossb_init(const char* manifest)
{

	//1. load manifest file
	if(!cossb_config->load(manifest))
		return false;

	//2. create(setup) instances according to the manifest
	if(!cossb_system_manager->setup(cossb_config))
		return false;

	return true;
}

void cossb_destroy()
{
	cossb_stop();
	cossb_log->log(log::loglevel::INFO, "Now terminating...");
	cossb_system_manager->destroy();
	cossb_config->destroy();
}

bool cossb_sync()
{
	return true;
}

bool cossb_start()
{
	cossb_log->log(log::loglevel::INFO, "Now all components is running...");
	if(cossb_component_manager->run())
		return true;

	return false;
}

bool cossb_stop()
{
	if(cossb_component_manager->count()>0)
	{
		cossb_log->log(log::loglevel::INFO, "Now all components is stopping...");
		if(cossb_component_manager->stop())
			return true;
	}

	return true;
}

} /* namespace core */
} /* namespace cossb */
<|endoftext|>


<commit_before>/* MULTEQ - multi-band equalizer instrument

   p0 = output start time
   p1 = input start time
   p2 = input duration
   p3 = amplitude multiplier
   p4 = master bypass (0: no, 1: yes)

   Followed by one or more (up to 8) EQ band descriptions, given by
   quintuplets of
        EQ type ("lowpass", "highpass", "lowshelf", "highshelf", "peaknotch") *
        filter frequency (Hz)
        filter Q (c. 0.5-10)
        filter gain (cut or boost, in dB -- for shelf and peak/notch only)
        bypass (0: no, 1: yes)

   So the settings for the first band would occupy pfields 5-9, the second,
   pfields 10-14, and so on.

   p3 (amplitude), p4 (bypass) as well as the freq, Q, gain and bypass pfields
   for individual bands can receive dynamic updates from a table or real-time
   control source.

   The EQ types can be updated only when using numeric codes (0: lowpass,
   1: highpass, 2: lowshelf, 3: highshelf, 4: peaknotch).  If you give the
   string version, you can't change types during a note.

   The number of input channels must equal the number of output channels.
   There can be as many as 8 channels.

   John Gibson <johgibso at indiana dot edu>, 26 Sep 2004; derived from EQ.

   Based on formulas by Robert Bristow-Johnson ("Audio-EQ-Cookbook") and code
   by Tom St Denis <tomstdenis.home.dhs.org> (see musicdsp.org)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ugens.h>
#include <math.h>
#include <Instrument.h>
#include <PField.h>
#include "MULTEQ.h"
#include <rt.h>
#include <rtdefs.h>
#include <float.h>   // for FLT_MIN

#define FIRST_BAND_PF 5
#define BAND_PFS      5

EQBand :: EQBand(float srate, OeqType type, float freq, float Q, float gain,
      bool bypass)
   : _type(type), _freq(freq), _Q(Q), _gain(gain), _bypass(bypass)
{
   _eq = new Oequalizer(srate, _type);
   if (_eq)
      _eq->setparams(_freq, _Q, _gain);
}

EQBand :: ~EQBand()
{
   delete _eq;
}

MULTEQ :: MULTEQ() : Instrument()
{
   in = NULL;
   branch = 0;
   for (int i = 0; i < MAXBAND * MAXCHAN; i++)
      eq[i] = NULL;
}

MULTEQ :: ~MULTEQ()
{
   delete [] in;
   for (int i = 0; i < MAXBAND * MAXCHAN; i++)
      delete eq[i];
}

static char *_eqtype_name[] = {
   "lowpass",     // 0
   "highpass",    // 1
   "lowshelf",    // 2
   "highshelf",   // 3
   "peaknotch",   // 4
   NULL
};

inline int _string_to_eqcode(const char *str)
{
   for (int i = 0; _eqtype_name[i] != NULL; i++)
      if (strncmp(str, _eqtype_name[i], 5) == 0)   // 5 is min. to distinguish
         return i;
   return -1;
}

OeqType MULTEQ :: getEQType(bool trystring, int pfindex)
{
   double index = (double) currentFrame() / nSamps();
   const PField &field = getPField(pfindex);

   // must try int first, since a valid code cast to char * will crash strncmp
   int code = field.intValue(index);
   if (trystring && (code < 0 || code > 4)) {
      const char *str = field.stringValue(index);
      code = _string_to_eqcode(str);   // -1 if no match
   }

   OeqType eqtype;
   switch (code) {
      case 0: eqtype = OeqLowPass;   break;
      case 1: eqtype = OeqHighPass;  break;
      case 2: eqtype = OeqLowShelf;  break;
      case 3: eqtype = OeqHighShelf; break;
      case 4: eqtype = OeqPeaking;   break;
      default: eqtype = OeqInvalid;  break;
   }
   return eqtype;
}

int MULTEQ :: init(double p[], int n_args)
{
   nargs = n_args;
   const float ringdur = 0.1;
   float outskip = p[0];
   float inskip = p[1];
   float dur = p[2];

   if (rtsetinput(inskip, this) == -1)
      return DONT_SCHEDULE;
   insamps = (int) (dur * SR + 0.5);

   if (rtsetoutput(outskip, dur + ringdur, this) == -1)
      return DONT_SCHEDULE;

   if (inputChannels() > MAXCHAN)
      return die("MULTEQ",
               "Input and output must have no more than %d channels.", MAXCHAN);
   if (outputChannels() != inputChannels())
      return die("MULTEQ", "Input and output must have same number of "
                           "channels, no more than %d.", MAXCHAN);

   if ((nargs - FIRST_BAND_PF) % BAND_PFS)
      return die("MULTEQ",
                 "For each band, need type, freq, Q, gain and bypass.");

   numbands = 0;
   int band = 0;
   for (int i = FIRST_BAND_PF; i < nargs; i += BAND_PFS, band += MAXCHAN) {
      if (numbands == MAXBAND) {
         warn("MULTEQ", "You can only have %d EQ bands.", MAXBAND);
         break;
      }

      OeqType type = getEQType(true, i);
      if (type == OeqInvalid)
         return die("MULTEQ", "Invalid EQ type string or code.");
      float freq = p[i + 1];
      float Q = p[i + 2];
      float gain = p[i + 3];
      bool bypass = (bool) p[i + 4];

      for (int c = 0; c < inputChannels(); c++) {
         eq[band + c] = new EQBand(SR, type, freq, Q, gain, bypass);
         if (eq[band + c] == NULL)
            return die("MULTEQ", "Can't allocate EQ band.");
      }

      numbands++;
   }

   skip = (int) (SR / (float) resetval);

   return nSamps();
}

void MULTEQ :: doupdate()
{
   double p[nargs];
   update(p, nargs);

   amp = p[3];
   bypass = (bool) p[4];

   int band = 0;
   for (int i = FIRST_BAND_PF; i < nargs; i += BAND_PFS, band += MAXCHAN) {
      OeqType type = getEQType(false, i);
      float freq = p[i + 1];
      if (freq < 0.0)
         freq = 0.0;
      else if (freq > SR * 0.5)
         freq = SR * 0.5;
      float Q = p[i + 2];
      if (Q <= 0.0)
         Q = FLT_MIN;
      float gain = p[i + 3];
      bool bypass = (bool) p[i + 4];

      for (int c = 0; c < inputChannels(); c++)
         eq[band + c]->setparams(type, freq, Q, gain, bypass);
   }
}

int MULTEQ :: configure()
{
   in = new float [RTBUFSAMPS * inputChannels()];
   return in ? 0 : -1;
}

int MULTEQ :: run()
{
   const int samps = framesToRun() * inputChannels();
   if (currentFrame() < insamps)
      rtgetin(in, this, samps);

   for (int i = 0; i < samps; i += inputChannels()) {
      if (--branch <= 0) {
         doupdate();
         branch = skip;
      }

      float insig[MAXCHAN];
      if (currentFrame() < insamps) {
         for (int c = 0; c < inputChannels(); c++)
            insig[c] = in[i + c];
      }
      else {
         for (int c = 0; c < inputChannels(); c++)
            insig[c] = 0.0;
      }

      float out[MAXCHAN];
      if (bypass) {
         for (int c = 0; c < inputChannels(); c++)
            out[c] = insig[c] * amp;
      }
      else {
         for (int c = 0; c < inputChannels(); c++) {
            for (int b = 0; b < numbands; b++) {
               int index = (b * MAXCHAN) + c;
               insig[c] = eq[index]->next(insig[c]);
            }
            out[c] = insig[c] * amp;
         }
      }

      rtaddout(out);
      increment();
   }

   return framesToRun();
}

Instrument *makeMULTEQ()
{
   MULTEQ *inst;

   inst = new MULTEQ();
   inst->set_bus_config("MULTEQ");

   return inst;
}

void rtprofile()
{
   RT_INTRO("MULTEQ", makeMULTEQ);
}

<commit_msg>Add bandpass type.<commit_after>/* MULTEQ - multi-band equalizer instrument

   p0 = output start time
   p1 = input start time
   p2 = input duration
   p3 = amplitude multiplier
   p4 = master bypass (0: no, 1: yes)

   Followed by one or more (up to 8) EQ band descriptions, given by
   quintuplets of
        EQ type ("lowpass", "highpass", "lowshelf", "highshelf", "peaknotch",
                 "bandpass") *
        filter frequency (Hz)
        filter Q (c. 0.5-10)
        filter gain (cut or boost, in dB -- for shelf and peak/notch only)
        bypass (0: no, 1: yes)

   So the settings for the first band would occupy pfields 5-9, the second,
   pfields 10-14, and so on.

   p3 (amplitude), p4 (bypass) as well as the freq, Q, gain and bypass pfields
   for individual bands can receive dynamic updates from a table or real-time
   control source.

   The EQ types can be updated only when using numeric codes (0: lowpass,
   1: highpass, 2: lowshelf, 3: highshelf, 4: peaknotch, 5: bandpass).  If
   you give the string version, you can't change types during a note.

   The number of input channels must equal the number of output channels.
   There can be as many as 8 channels.

   John Gibson <johgibso at indiana dot edu>, 26 Sep 2004; derived from EQ.

   Based on formulas by Robert Bristow-Johnson ("Audio-EQ-Cookbook") and code
   by Tom St Denis <tomstdenis.home.dhs.org> (see musicdsp.org)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ugens.h>
#include <math.h>
#include <Instrument.h>
#include <PField.h>
#include "MULTEQ.h"
#include <rt.h>
#include <rtdefs.h>
#include <float.h>   // for FLT_MIN

#define FIRST_BAND_PF 5
#define BAND_PFS      5

EQBand :: EQBand(float srate, OeqType type, float freq, float Q, float gain,
      bool bypass)
   : _type(type), _freq(freq), _Q(Q), _gain(gain), _bypass(bypass)
{
   _eq = new Oequalizer(srate, _type);
   if (_eq)
      _eq->setparams(_freq, _Q, _gain);
}

EQBand :: ~EQBand()
{
   delete _eq;
}

MULTEQ :: MULTEQ() : Instrument()
{
   in = NULL;
   branch = 0;
   for (int i = 0; i < MAXBAND * MAXCHAN; i++)
      eq[i] = NULL;
}

MULTEQ :: ~MULTEQ()
{
   delete [] in;
   for (int i = 0; i < MAXBAND * MAXCHAN; i++)
      delete eq[i];
}

static char *_eqtype_name[] = {
   "lowpass",     // 0
   "highpass",    // 1
   "lowshelf",    // 2
   "highshelf",   // 3
   "peaknotch",   // 4
   "bandpass",    // 5
   NULL
};

inline int _string_to_eqcode(const char *str)
{
   for (int i = 0; _eqtype_name[i] != NULL; i++)
      if (strncmp(str, _eqtype_name[i], 5) == 0)   // 5 is min. to distinguish
         return i;
   return -1;
}

OeqType MULTEQ :: getEQType(bool trystring, int pfindex)
{
   double index = (double) currentFrame() / nSamps();
   const PField &field = getPField(pfindex);

   // must try int first, since a valid code cast to char * will crash strncmp
   int code = field.intValue(index);
   if (trystring && (code < 0 || code > 4)) {
      const char *str = field.stringValue(index);
      code = _string_to_eqcode(str);   // -1 if no match
   }

   OeqType eqtype;
   switch (code) {
      case 0: eqtype = OeqLowPass;   break;
      case 1: eqtype = OeqHighPass;  break;
      case 2: eqtype = OeqLowShelf;  break;
      case 3: eqtype = OeqHighShelf; break;
      case 4: eqtype = OeqPeaking;   break;
      case 5: eqtype = OeqBandPassCSG; break;
      default: eqtype = OeqInvalid;  break;
   }
   return eqtype;
}

int MULTEQ :: init(double p[], int n_args)
{
   nargs = n_args;
   const float ringdur = 0.1;
   float outskip = p[0];
   float inskip = p[1];
   float dur = p[2];

   if (rtsetinput(inskip, this) == -1)
      return DONT_SCHEDULE;
   insamps = (int) (dur * SR + 0.5);

   if (rtsetoutput(outskip, dur + ringdur, this) == -1)
      return DONT_SCHEDULE;

   if (inputChannels() > MAXCHAN)
      return die("MULTEQ",
               "Input and output must have no more than %d channels.", MAXCHAN);
   if (outputChannels() != inputChannels())
      return die("MULTEQ", "Input and output must have same number of "
                           "channels, no more than %d.", MAXCHAN);

   if ((nargs - FIRST_BAND_PF) % BAND_PFS)
      return die("MULTEQ",
                 "For each band, need type, freq, Q, gain and bypass.");

   numbands = 0;
   int band = 0;
   for (int i = FIRST_BAND_PF; i < nargs; i += BAND_PFS, band += MAXCHAN) {
      if (numbands == MAXBAND) {
         warn("MULTEQ", "You can only have %d EQ bands.", MAXBAND);
         break;
      }

      OeqType type = getEQType(true, i);
      if (type == OeqInvalid)
         return die("MULTEQ", "Invalid EQ type string or code.");
      float freq = p[i + 1];
      float Q = p[i + 2];
      float gain = p[i + 3];
      bool bypass = (bool) p[i + 4];

      for (int c = 0; c < inputChannels(); c++) {
         eq[band + c] = new EQBand(SR, type, freq, Q, gain, bypass);
         if (eq[band + c] == NULL)
            return die("MULTEQ", "Can't allocate EQ band.");
      }

      numbands++;
   }

   skip = (int) (SR / (float) resetval);

   return nSamps();
}

void MULTEQ :: doupdate()
{
   double p[nargs];
   update(p, nargs);

   amp = p[3];
   bypass = (bool) p[4];

   int band = 0;
   for (int i = FIRST_BAND_PF; i < nargs; i += BAND_PFS, band += MAXCHAN) {
      OeqType type = getEQType(false, i);
      float freq = p[i + 1];
      if (freq < 0.0)
         freq = 0.0;
      else if (freq > SR * 0.5)
         freq = SR * 0.5;
      float Q = p[i + 2];
      if (Q <= 0.0)
         Q = FLT_MIN;
      float gain = p[i + 3];
      bool bypass = (bool) p[i + 4];

      for (int c = 0; c < inputChannels(); c++)
         eq[band + c]->setparams(type, freq, Q, gain, bypass);
   }
}

int MULTEQ :: configure()
{
   in = new float [RTBUFSAMPS * inputChannels()];
   return in ? 0 : -1;
}

int MULTEQ :: run()
{
   const int samps = framesToRun() * inputChannels();
   if (currentFrame() < insamps)
      rtgetin(in, this, samps);

   for (int i = 0; i < samps; i += inputChannels()) {
      if (--branch <= 0) {
         doupdate();
         branch = skip;
      }

      float insig[MAXCHAN];
      if (currentFrame() < insamps) {
         for (int c = 0; c < inputChannels(); c++)
            insig[c] = in[i + c];
      }
      else {
         for (int c = 0; c < inputChannels(); c++)
            insig[c] = 0.0;
      }

      float out[MAXCHAN];
      if (bypass) {
         for (int c = 0; c < inputChannels(); c++)
            out[c] = insig[c] * amp;
      }
      else {
         for (int c = 0; c < inputChannels(); c++) {
            for (int b = 0; b < numbands; b++) {
               int index = (b * MAXCHAN) + c;
               insig[c] = eq[index]->next(insig[c]);
            }
            out[c] = insig[c] * amp;
         }
      }

      rtaddout(out);
      increment();
   }

   return framesToRun();
}

Instrument *makeMULTEQ()
{
   MULTEQ *inst;

   inst = new MULTEQ();
   inst->set_bus_config("MULTEQ");

   return inst;
}

void rtprofile()
{
   RT_INTRO("MULTEQ", makeMULTEQ);
}

<|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
*                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* 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 Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_PROJECTIVECONSTRAINTSET_FIXEDCONSTRAINT_INL
#define SOFA_COMPONENT_PROJECTIVECONSTRAINTSET_FIXEDCONSTRAINT_INL

#include <sofa/core/topology/BaseMeshTopology.h>
#include <sofa/core/behavior/ProjectiveConstraintSet.inl>
#include <sofa/component/projectiveconstraintset/FixedConstraint.h>
#include <sofa/component/topology/PointSubset.h>
#include <sofa/simulation/common/Simulation.h>
#include <sofa/helper/gl/template.h>
#include <sofa/defaulttype/RigidTypes.h>
#include <iostream>

#include <sofa/helper/gl/BasicShapes.h>

namespace sofa
{

namespace component
{

namespace projectiveconstraintset
{

using namespace core::topology;

using namespace sofa::defaulttype;
using namespace sofa::helper;
using namespace sofa::core::behavior;

// Define TestNewPointFunction
template< class DataTypes>
bool FixedConstraint<DataTypes>::FCTestNewPointFunction(int /*nbPoints*/, void* param, const sofa::helper::vector< unsigned int > &, const sofa::helper::vector< double >& )
{
    FixedConstraint<DataTypes> *fc= (FixedConstraint<DataTypes> *)param;
    if (fc)
    {
        return true;
    }
    else
    {
        return false;
    }
}

// Define RemovalFunction
template< class DataTypes>
void FixedConstraint<DataTypes>::FCRemovalFunction(int pointIndex, void* param)
{
    FixedConstraint<DataTypes> *fc= (FixedConstraint<DataTypes> *)param;
    if (fc)
    {
        fc->removeConstraint((unsigned int) pointIndex);
    }
    return;
}

template <class DataTypes>
FixedConstraint<DataTypes>::FixedConstraint()
    : core::behavior::ProjectiveConstraintSet<DataTypes>(NULL)
    , f_indices( initData(&f_indices,"indices","Indices of the fixed points") )
    , f_fixAll( initData(&f_fixAll,false,"fixAll","filter all the DOF to implement a fixed object") )
    , _drawSize( initData(&_drawSize,0.0,"drawSize","0 -> point based rendering, >0 -> radius of spheres") )
{
    // default to indice 0
    f_indices.beginEdit()->push_back(0);
    f_indices.endEdit();
}

// Handle topological changes
template <class DataTypes> void FixedConstraint<DataTypes>::handleTopologyChange()
{
    std::list<const TopologyChange *>::const_iterator itBegin=topology->beginChange();
    std::list<const TopologyChange *>::const_iterator itEnd=topology->endChange();

    f_indices.beginEdit()->handleTopologyEvents(itBegin,itEnd,this->getMState()->getSize());

}

template <class DataTypes>
FixedConstraint<DataTypes>::~FixedConstraint()
{
}

template <class DataTypes>
void FixedConstraint<DataTypes>::clearConstraints()
{
    f_indices.beginEdit()->clear();
    f_indices.endEdit();
}

template <class DataTypes>
void FixedConstraint<DataTypes>::addConstraint(unsigned int index)
{
    f_indices.beginEdit()->push_back(index);
    f_indices.endEdit();
}

template <class DataTypes>
void FixedConstraint<DataTypes>::removeConstraint(unsigned int index)
{
    removeValue(*f_indices.beginEdit(),index);
    f_indices.endEdit();
}

// -- Constraint interface

template <class DataTypes>
void FixedConstraint<DataTypes>::init()
{
    this->core::behavior::ProjectiveConstraintSet<DataTypes>::init();

    topology = this->getContext()->getMeshTopology();

//  if (!topology)
//    serr << "Can not find the topology." << sendl;

    // Initialize functions and parameters
    topology::PointSubset my_subset = f_indices.getValue();

    my_subset.setTestFunction(FCTestNewPointFunction);
    my_subset.setRemovalFunction(FCRemovalFunction);

    my_subset.setTestParameter( (void *) this );
    my_subset.setRemovalParameter( (void *) this );

    unsigned int maxIndex=this->mstate->getSize();
    for (topology::PointSubset::iterator it = my_subset.begin();  it != my_subset.end(); )
    {
        topology::PointSubset::iterator currentIterator=it;
        const unsigned int index=*it;
        it++;
        if (index >= maxIndex)
        {
            serr << "Index " << index << " not valid!" << sendl;
            removeConstraint(index);
        }
    }

}

template <class DataTypes>
void FixedConstraint<DataTypes>::projectResponse(const core::MechanicalParams* mparams /* PARAMS FIRST */, DataVecDeriv& resData)
{
    //cerr<<"FixedConstraint<DataTypes>::projectResponse is called "<<endl;
    helper::WriteAccessor<DataVecDeriv> res ( mparams, resData );
    const SetIndexArray & indices = f_indices.getValue(mparams).getArray();
    //serr<<"FixedConstraint<DataTypes>::projectResponse, dx.size()="<<res.size()<<sendl;
    if( f_fixAll.getValue(mparams) )
    {
        // fix everything
        for( int i=0; i<topology->getNbPoints(); ++i )
            res[i] = Deriv();
    }
    else
    {
        for (SetIndexArray::const_iterator it = indices.begin();
                it != indices.end();
                ++it)
        {
            res[*it] = Deriv();
        }
    }
    //cerr<<"FixedConstraint<DataTypes>::projectResponse is called  res = "<<endl<<res<<endl;
}

template <class DataTypes>
void FixedConstraint<DataTypes>::projectJacobianMatrix(const core::MechanicalParams* mparams /* PARAMS FIRST */, DataMatrixDeriv& cData)
{
    helper::WriteAccessor<DataMatrixDeriv> c ( mparams, cData );
    const SetIndexArray & indices = f_indices.getValue(mparams).getArray();

    MatrixDerivRowIterator rowIt = c->begin();
    MatrixDerivRowIterator rowItEnd = c->end();

    if( f_fixAll.getValue(mparams) )
    {
        // fix everything
        while (rowIt != rowItEnd)
        {
            rowIt.row().clear();
            ++rowIt;
        }
    }
    else
    {
        while (rowIt != rowItEnd)
        {
            for (SetIndexArray::const_iterator it = indices.begin();
                    it != indices.end();
                    ++it)
            {
                rowIt.row().erase(*it);
            }
            ++rowIt;
        }
    }
    //cerr<<"FixedConstraint<DataTypes>::projectJacobianMatrix : helper::WriteAccessor<DataMatrixDeriv> c =  "<<endl<< c<<endl;
}

// projectVelocity applies the same changes on velocity vector as projectResponse on position vector :
// Each fixed point received a null velocity vector.
// When a new fixed point is added while its velocity vector is already null, projectVelocity is not usefull.
// But when a new fixed point is added while its velocity vector is not null, it's necessary to fix it to null. If not, the fixed point is going to drift.
template <class DataTypes>
void FixedConstraint<DataTypes>::projectVelocity(const core::MechanicalParams* /*mparams*/ /* PARAMS FIRST */, DataVecDeriv& /*vData*/)
{
#if 0 /// @TODO ADD A FLAG FOR THIS
    const SetIndexArray & indices = f_indices.getValue().getArray();
    //serr<<"FixedConstraint<DataTypes>::projectVelocity, res.size()="<<res.size()<<sendl;
    if( f_fixAll.getValue()==true )    // fix everyting
    {
        for( unsigned i=0; i<res.size(); i++ )
            res[i] = Deriv();
    }
    else
    {
        for (SetIndexArray::const_iterator it = indices.begin();
                it != indices.end();
                ++it)
        {
            res[*it] = Deriv();
        }
    }
#endif
}

template <class DataTypes>
void FixedConstraint<DataTypes>::projectPosition(const core::MechanicalParams* /*mparams*/ /* PARAMS FIRST */, DataVecCoord& /*xData*/)
{

}

// Matrix Integration interface
template <class DataTypes>
void FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseMatrix *mat, unsigned int offset)
{
    //sout << "applyConstraint in Matrix with offset = " << offset << sendl;
    //cerr<<"FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseMatrix *mat, unsigned int offset) is called "<<endl;
    const unsigned int N = Deriv::size();
    const SetIndexArray & indices = f_indices.getValue().getArray();

    for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it)
    {
        // Reset Fixed Row and Col
        for (unsigned int c=0; c<N; ++c)
            mat->clearRowCol(offset + N * (*it) + c);
        // Set Fixed Vertex
        for (unsigned int c=0; c<N; ++c)
            mat->set(offset + N * (*it) + c, offset + N * (*it) + c, 1.0);
    }
}

template <class DataTypes>
void FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseVector *vect, unsigned int offset)
{
    //cerr<<"FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseVector *vect, unsigned int offset) is called "<<endl;
    //sout << "applyConstraint in Vector with offset = " << offset << sendl;
    const unsigned int N = Deriv::size();

    const SetIndexArray & indices = f_indices.getValue().getArray();
    for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it)
    {
        for (unsigned int c=0; c<N; ++c)
            vect->clear(offset + N * (*it) + c);
    }
}

template <class DataTypes>
void FixedConstraint<DataTypes>::draw()
{
    if (!this->getContext()->
        getShowBehaviorModels()) return;
    if (!this->isActive()) return;
    const VecCoord& x = *this->mstate->getX();
    //serr<<"FixedConstraint<DataTypes>::draw(), x.size() = "<<x.size()<<sendl;

    const SetIndexArray & indices = f_indices.getValue().getArray();

    if( _drawSize.getValue() == 0) // old classical drawing by points
    {
        std::vector< Vector3 > points;
        Vector3 point;
        //serr<<"FixedConstraint<DataTypes>::draw(), indices = "<<indices<<sendl;
        if( f_fixAll.getValue() )
            for (unsigned i=0; i<x.size(); i++ )
            {
                point = DataTypes::getCPos(x[i]);
                points.push_back(point);
            }
        else
            for (SetIndexArray::const_iterator it = indices.begin();
                    it != indices.end();
                    ++it)
            {
                point = DataTypes::getCPos(x[*it]);
                points.push_back(point);
            }
        simulation::getSimulation()->DrawUtility().drawPoints(points, 10, Vec<4,float>(1,0.5,0.5,1));
    }
    else // new drawing by spheres
    {
        std::vector< Vector3 > points;
        Vector3 point;
        glColor4f (1.0f,0.35f,0.35f,1.0f);
        if( f_fixAll.getValue()==true )
            for (unsigned i=0; i<x.size(); i++ )
            {
                point = DataTypes::getCPos(x[i]);
                points.push_back(point);
            }
        else
            for (SetIndexArray::const_iterator it = indices.begin();
                    it != indices.end();
                    ++it)
            {
                point = DataTypes::getCPos(x[*it]);
                points.push_back(point);
            }
        simulation::getSimulation()->DrawUtility().drawSpheres(points, (float)_drawSize.getValue(), Vec<4,float>(1.0f,0.35f,0.35f,1.0f));
    }
}

// Specialization for rigids
#ifndef SOFA_FLOAT
template <>
void FixedConstraint<Rigid3dTypes >::draw();
template <>
void FixedConstraint<Rigid2dTypes >::draw();
#endif
#ifndef SOFA_DOUBLE
template <>
void FixedConstraint<Rigid3fTypes >::draw();
template <>
void FixedConstraint<Rigid2fTypes >::draw();
#endif

} // namespace constraint

} // namespace component

} // namespace sofa

#endif

<commit_msg>r10100/sofa-dev : FIX: bug in FixedConstraint::projectResponse() see ticket#236<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
*                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
*                                                                             *
* 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 Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                               SOFA :: Modules                               *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFA_COMPONENT_PROJECTIVECONSTRAINTSET_FIXEDCONSTRAINT_INL
#define SOFA_COMPONENT_PROJECTIVECONSTRAINTSET_FIXEDCONSTRAINT_INL

#include <sofa/core/topology/BaseMeshTopology.h>
#include <sofa/core/behavior/ProjectiveConstraintSet.inl>
#include <sofa/component/projectiveconstraintset/FixedConstraint.h>
#include <sofa/component/topology/PointSubset.h>
#include <sofa/simulation/common/Simulation.h>
#include <sofa/helper/gl/template.h>
#include <sofa/defaulttype/RigidTypes.h>
#include <iostream>

#include <sofa/helper/gl/BasicShapes.h>

namespace sofa
{

namespace component
{

namespace projectiveconstraintset
{

using namespace core::topology;

using namespace sofa::defaulttype;
using namespace sofa::helper;
using namespace sofa::core::behavior;

// Define TestNewPointFunction
template< class DataTypes>
bool FixedConstraint<DataTypes>::FCTestNewPointFunction(int /*nbPoints*/, void* param, const sofa::helper::vector< unsigned int > &, const sofa::helper::vector< double >& )
{
    FixedConstraint<DataTypes> *fc= (FixedConstraint<DataTypes> *)param;
    if (fc)
    {
        return true;
    }
    else
    {
        return false;
    }
}

// Define RemovalFunction
template< class DataTypes>
void FixedConstraint<DataTypes>::FCRemovalFunction(int pointIndex, void* param)
{
    FixedConstraint<DataTypes> *fc= (FixedConstraint<DataTypes> *)param;
    if (fc)
    {
        fc->removeConstraint((unsigned int) pointIndex);
    }
    return;
}

template <class DataTypes>
FixedConstraint<DataTypes>::FixedConstraint()
    : core::behavior::ProjectiveConstraintSet<DataTypes>(NULL)
    , f_indices( initData(&f_indices,"indices","Indices of the fixed points") )
    , f_fixAll( initData(&f_fixAll,false,"fixAll","filter all the DOF to implement a fixed object") )
    , _drawSize( initData(&_drawSize,0.0,"drawSize","0 -> point based rendering, >0 -> radius of spheres") )
{
    // default to indice 0
    f_indices.beginEdit()->push_back(0);
    f_indices.endEdit();
}

// Handle topological changes
template <class DataTypes> void FixedConstraint<DataTypes>::handleTopologyChange()
{
    std::list<const TopologyChange *>::const_iterator itBegin=topology->beginChange();
    std::list<const TopologyChange *>::const_iterator itEnd=topology->endChange();

    f_indices.beginEdit()->handleTopologyEvents(itBegin,itEnd,this->getMState()->getSize());

}

template <class DataTypes>
FixedConstraint<DataTypes>::~FixedConstraint()
{
}

template <class DataTypes>
void FixedConstraint<DataTypes>::clearConstraints()
{
    f_indices.beginEdit()->clear();
    f_indices.endEdit();
}

template <class DataTypes>
void FixedConstraint<DataTypes>::addConstraint(unsigned int index)
{
    f_indices.beginEdit()->push_back(index);
    f_indices.endEdit();
}

template <class DataTypes>
void FixedConstraint<DataTypes>::removeConstraint(unsigned int index)
{
    removeValue(*f_indices.beginEdit(),index);
    f_indices.endEdit();
}

// -- Constraint interface

template <class DataTypes>
void FixedConstraint<DataTypes>::init()
{
    this->core::behavior::ProjectiveConstraintSet<DataTypes>::init();

    topology = this->getContext()->getMeshTopology();

//  if (!topology)
//    serr << "Can not find the topology." << sendl;

    // Initialize functions and parameters
    topology::PointSubset my_subset = f_indices.getValue();

    my_subset.setTestFunction(FCTestNewPointFunction);
    my_subset.setRemovalFunction(FCRemovalFunction);

    my_subset.setTestParameter( (void *) this );
    my_subset.setRemovalParameter( (void *) this );

    unsigned int maxIndex=this->mstate->getSize();
    for (topology::PointSubset::iterator it = my_subset.begin();  it != my_subset.end(); )
    {
        topology::PointSubset::iterator currentIterator=it;
        const unsigned int index=*it;
        it++;
        if (index >= maxIndex)
        {
            serr << "Index " << index << " not valid!" << sendl;
            removeConstraint(index);
        }
    }

}

template <class DataTypes>
void FixedConstraint<DataTypes>::projectResponse(const core::MechanicalParams* mparams /* PARAMS FIRST */, DataVecDeriv& resData)
{
    //cerr<<"FixedConstraint<DataTypes>::projectResponse is called "<<endl;
    helper::WriteAccessor<DataVecDeriv> res ( mparams, resData );
    const SetIndexArray & indices = f_indices.getValue(mparams).getArray();
    //serr<<"FixedConstraint<DataTypes>::projectResponse, dx.size()="<<res.size()<<sendl;
    if( f_fixAll.getValue(mparams) )
    {
        // fix everything
        typename VecDeriv::iterator it;
        for( it = res.begin(); it != res.end(); ++it )
        {
            *it = Deriv();
        }
    }
    else
    {
        for (SetIndexArray::const_iterator it = indices.begin();
                it != indices.end();
                ++it)
        {
            res[*it] = Deriv();
        }
    }
    //cerr<<"FixedConstraint<DataTypes>::projectResponse is called  res = "<<endl<<res<<endl;
}

template <class DataTypes>
void FixedConstraint<DataTypes>::projectJacobianMatrix(const core::MechanicalParams* mparams /* PARAMS FIRST */, DataMatrixDeriv& cData)
{
    helper::WriteAccessor<DataMatrixDeriv> c ( mparams, cData );
    const SetIndexArray & indices = f_indices.getValue(mparams).getArray();

    MatrixDerivRowIterator rowIt = c->begin();
    MatrixDerivRowIterator rowItEnd = c->end();

    if( f_fixAll.getValue(mparams) )
    {
        // fix everything
        while (rowIt != rowItEnd)
        {
            rowIt.row().clear();
            ++rowIt;
        }
    }
    else
    {
        while (rowIt != rowItEnd)
        {
            for (SetIndexArray::const_iterator it = indices.begin();
                    it != indices.end();
                    ++it)
            {
                rowIt.row().erase(*it);
            }
            ++rowIt;
        }
    }
    //cerr<<"FixedConstraint<DataTypes>::projectJacobianMatrix : helper::WriteAccessor<DataMatrixDeriv> c =  "<<endl<< c<<endl;
}

// projectVelocity applies the same changes on velocity vector as projectResponse on position vector :
// Each fixed point received a null velocity vector.
// When a new fixed point is added while its velocity vector is already null, projectVelocity is not usefull.
// But when a new fixed point is added while its velocity vector is not null, it's necessary to fix it to null. If not, the fixed point is going to drift.
template <class DataTypes>
void FixedConstraint<DataTypes>::projectVelocity(const core::MechanicalParams* /*mparams*/ /* PARAMS FIRST */, DataVecDeriv& /*vData*/)
{
#if 0 /// @TODO ADD A FLAG FOR THIS
    const SetIndexArray & indices = f_indices.getValue().getArray();
    //serr<<"FixedConstraint<DataTypes>::projectVelocity, res.size()="<<res.size()<<sendl;
    if( f_fixAll.getValue()==true )    // fix everyting
    {
        for( unsigned i=0; i<res.size(); i++ )
            res[i] = Deriv();
    }
    else
    {
        for (SetIndexArray::const_iterator it = indices.begin();
                it != indices.end();
                ++it)
        {
            res[*it] = Deriv();
        }
    }
#endif
}

template <class DataTypes>
void FixedConstraint<DataTypes>::projectPosition(const core::MechanicalParams* /*mparams*/ /* PARAMS FIRST */, DataVecCoord& /*xData*/)
{

}

// Matrix Integration interface
template <class DataTypes>
void FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseMatrix *mat, unsigned int offset)
{
    //sout << "applyConstraint in Matrix with offset = " << offset << sendl;
    //cerr<<"FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseMatrix *mat, unsigned int offset) is called "<<endl;
    const unsigned int N = Deriv::size();
    const SetIndexArray & indices = f_indices.getValue().getArray();

    for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it)
    {
        // Reset Fixed Row and Col
        for (unsigned int c=0; c<N; ++c)
            mat->clearRowCol(offset + N * (*it) + c);
        // Set Fixed Vertex
        for (unsigned int c=0; c<N; ++c)
            mat->set(offset + N * (*it) + c, offset + N * (*it) + c, 1.0);
    }
}

template <class DataTypes>
void FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseVector *vect, unsigned int offset)
{
    //cerr<<"FixedConstraint<DataTypes>::applyConstraint(defaulttype::BaseVector *vect, unsigned int offset) is called "<<endl;
    //sout << "applyConstraint in Vector with offset = " << offset << sendl;
    const unsigned int N = Deriv::size();

    const SetIndexArray & indices = f_indices.getValue().getArray();
    for (SetIndexArray::const_iterator it = indices.begin(); it != indices.end(); ++it)
    {
        for (unsigned int c=0; c<N; ++c)
            vect->clear(offset + N * (*it) + c);
    }
}

template <class DataTypes>
void FixedConstraint<DataTypes>::draw()
{
    if (!this->getContext()->
        getShowBehaviorModels()) return;
    if (!this->isActive()) return;
    const VecCoord& x = *this->mstate->getX();
    //serr<<"FixedConstraint<DataTypes>::draw(), x.size() = "<<x.size()<<sendl;

    const SetIndexArray & indices = f_indices.getValue().getArray();

    if( _drawSize.getValue() == 0) // old classical drawing by points
    {
        std::vector< Vector3 > points;
        Vector3 point;
        //serr<<"FixedConstraint<DataTypes>::draw(), indices = "<<indices<<sendl;
        if( f_fixAll.getValue() )
            for (unsigned i=0; i<x.size(); i++ )
            {
                point = DataTypes::getCPos(x[i]);
                points.push_back(point);
            }
        else
            for (SetIndexArray::const_iterator it = indices.begin();
                    it != indices.end();
                    ++it)
            {
                point = DataTypes::getCPos(x[*it]);
                points.push_back(point);
            }
        simulation::getSimulation()->DrawUtility().drawPoints(points, 10, Vec<4,float>(1,0.5,0.5,1));
    }
    else // new drawing by spheres
    {
        std::vector< Vector3 > points;
        Vector3 point;
        glColor4f (1.0f,0.35f,0.35f,1.0f);
        if( f_fixAll.getValue()==true )
            for (unsigned i=0; i<x.size(); i++ )
            {
                point = DataTypes::getCPos(x[i]);
                points.push_back(point);
            }
        else
            for (SetIndexArray::const_iterator it = indices.begin();
                    it != indices.end();
                    ++it)
            {
                point = DataTypes::getCPos(x[*it]);
                points.push_back(point);
            }
        simulation::getSimulation()->DrawUtility().drawSpheres(points, (float)_drawSize.getValue(), Vec<4,float>(1.0f,0.35f,0.35f,1.0f));
    }
}

// Specialization for rigids
#ifndef SOFA_FLOAT
template <>
void FixedConstraint<Rigid3dTypes >::draw();
template <>
void FixedConstraint<Rigid2dTypes >::draw();
#endif
#ifndef SOFA_DOUBLE
template <>
void FixedConstraint<Rigid3fTypes >::draw();
template <>
void FixedConstraint<Rigid2fTypes >::draw();
#endif

} // namespace constraint

} // namespace component

} // namespace sofa

#endif

<|endoftext|>