text:
///////////////////////////////////////////////////////////////////////////////
// Copyright Christopher Kormanyos 2014.
// Copyright John Maddock 2014.
// Copyright Paul Bristow 2014.
// Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
//

// Implement quadruple-precision I/O stream operations.

#ifndef BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_
  #define BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_

  #include <boost/math/cstdfloat/cstdfloat_types.hpp>
  #include <boost/math/cstdfloat/cstdfloat_limits.hpp>
  #include <boost/math/cstdfloat/cstdfloat_cmath.hpp>

  #if defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH)
  #error You can not use <boost/math/cstdfloat/cstdfloat_iostream.hpp> with BOOST_CSTDFLOAT_NO_LIBQUADMATH_CMATH defined.
  #endif

  #if defined(BOOST_CSTDFLOAT_HAS_INTERNAL_FLOAT128_T) && defined(BOOST_MATH_USE_FLOAT128) && !defined(BOOST_CSTDFLOAT_NO_LIBQUADMATH_SUPPORT)

  #include <cstddef>
  #include <istream>
  #include <ostream>
  #include <sstream>
  #include <stdexcept>
  #include <string>
  #include <boost/static_assert.hpp>
  #include <boost/throw_exception.hpp>

//  #if (0)
  #if defined(__GNUC__)

  // Forward declarations of quadruple-precision string functions.
  extern "C" int quadmath_snprintf(char *str, size_t size, const char *format, ...) throw();
  extern "C" boost::math::cstdfloat::detail::float_internal128_t strtoflt128(const char*, char **) throw();

  namespace std
  {
    template<typename char_type, class traits_type>
    inline std::basic_ostream<char_type, traits_type>& operator<<(std::basic_ostream<char_type, traits_type>& os, const boost::math::cstdfloat::detail::float_internal128_t& x)
    {
      std::basic_ostringstream<char_type, traits_type> ostr;
      ostr.flags(os.flags());
      ostr.imbue(os.getloc());
      ostr.precision(os.precision());

      char my_buffer[64U];

      const int my_prec   = static_cast<int>(os.precision());
      const int my_digits = ((my_prec == 0) ? 36 : my_prec);

      const std::ios_base::fmtflags my_flags  = os.flags();

      char my_format_string[8U];

      std::size_t my_format_string_index = 0U;

      my_format_string[my_format_string_index] = '%';
      ++my_format_string_index;

      if(my_flags & std::ios_base::showpos)   { my_format_string[my_format_string_index] = '+'; ++my_format_string_index; }
      if(my_flags & std::ios_base::showpoint) { my_format_string[my_format_string_index] = '#'; ++my_format_string_index; }

      my_format_string[my_format_string_index + 0U] = '.';
      my_format_string[my_format_string_index + 1U] = '*';
      my_format_string[my_format_string_index + 2U] = 'Q';

      my_format_string_index += 3U;

      char the_notation_char;

      if     (my_flags & std::ios_base::scientific) { the_notation_char = 'e'; }
      else if(my_flags & std::ios_base::fixed)      { the_notation_char = 'f'; }
      else                                          { the_notation_char = 'g'; }

      my_format_string[my_format_string_index + 0U] = the_notation_char;
      my_format_string[my_format_string_index + 1U] = 0;

      const int v = ::quadmath_snprintf(my_buffer,
                                        static_cast<int>(sizeof(my_buffer)),
                                        my_format_string,
                                        my_digits,
                                        x);

      if(v < 0) { BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed internally in quadmath_snprintf().")); }

      if(v >= static_cast<int>(sizeof(my_buffer) - 1U))
      {
        // Evidently there is a really long floating-point string here,
        // such as a small decimal representation in non-scientific notation.
        // So we have to use dynamic memory allocation for the output
        // string buffer.

        char* my_buffer2 = static_cast<char*>(0U);

#ifndef BOOST_NO_EXCEPTIONS
        try
        {
#endif
          my_buffer2 = new char[v + 3];
#ifndef BOOST_NO_EXCEPTIONS
        }
        catch(const std::bad_alloc&)
        {
          BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed while allocating memory."));
        }
#endif
        const int v2 = ::quadmath_snprintf(my_buffer2,
                                            v + 3,
                                            my_format_string,
                                            my_digits,
                                            x);

        if(v2 >= v + 3)
        {
          BOOST_THROW_EXCEPTION(std::runtime_error("Formatting of boost::float128_t failed."));
        }

        static_cast<void>(ostr << my_buffer2);

        delete [] my_buffer2;
      }
      else
      {
        static_cast<void>(ostr << my_buffer);
      }

      return (os << ostr.str());
    }

    template<typename char_type, class traits_type>
    inline std::basic_istream<char_type, traits_type>& operator>>(std::basic_istream<char_type, traits_type>& is, boost::math::cstdfloat::detail::float_internal128_t& x)
    {
      std::string str;

      static_cast<void>(is >> str);

      char* p_end;

      x = strtoflt128(str.c_str(), &p_end);

      if(static_cast<std::ptrdiff_t>(p_end - str.c_str()) != static_cast<std::ptrdiff_t>(str.length()))
      {
        for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it)
        {
          static_cast<void>(is.putback(*it));
        }

        is.setstate(ios_base::failbit);

        BOOST_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t"));
      }

      return is;
    }
  }

//  #elif defined(__GNUC__)
  #elif defined(BOOST_INTEL)

  // The section for I/O stream support for the ICC compiler is particularly
  // long, because these functions must be painstakingly synthesized from
  // manually-written routines (ICC does not support I/O stream operations
  // for its _Quad type).

  // The following string-extraction routines are based on the methodology
  // used in Boost.Multiprecision by John Maddock and Christopher Kormanyos.
  // This methodology has been slightly modified here for boost::float128_t.

  #include <cstring>
  #include <cctype>
  #include <boost/lexical_cast.hpp>

  namespace boost { namespace math { namespace cstdfloat { namespace detail {

  template<class string_type>
  void format_float_string(string_type& str,
                            int my_exp,
                            int digits,
                            const std::ios_base::fmtflags f,
                            const bool iszero)
  {
    typedef typename string_type::size_type size_type;

    const bool scientific = ((f & std::ios_base::scientific) == std::ios_base::scientific);
    const bool fixed      = ((f & std::ios_base::fixed)      == std::ios_base::fixed);
    const bool showpoint  = ((f & std::ios_base::showpoint)  == std::ios_base::showpoint);
    const bool showpos    = ((f & std::ios_base::showpos)    == std::ios_base::showpos);

    const bool b_neg = ((str.size() != 0U) && (str[0] == '-'));

    if(b_neg)
    {
      str.erase(0, 1);
    }

    if(digits == 0)
    {
      digits = static_cast<int>((std::max)(str.size(), size_type(16)));
    }

    if(iszero || str.empty() || (str.find_first_not_of('0') == string_type::npos))
    {
      // We will be printing zero, even though the value might not
      // actually be zero (it just may have been rounded to zero).
      str = "0";

      if(scientific || fixed)
      {
        str.append(1, '.');
        str.append(size_type(digits), '0');

        if(scientific)
        {
          str.append("e+00");
        }
      }
      else
      {
        if(showpoint)
        {
          str.append(1, '.');
          if(digits > 1)
          {
            str.append(size_type(digits - 1), '0');
          }
        }
      }

      if(b_neg)
      {
        str.insert(0U, 1U, '-');
      }
      else if(showpos)
      {
        str.insert(0U, 1U, '+');
      }

      return;
    }

    if(!fixed && !scientific && !showpoint)
    {
      // Suppress trailing zeros.
      typename string_type::iterator pos = str.end();

      while(pos != str.begin() && *--pos == '0') { ; }

      if(pos != str.end())
      {
        ++pos;
      }

      str.erase(pos, str.end());

      if(str.empty())
      {
        str = '0';
      }
    }
    else if(!fixed || (my_exp >= 0))
    {
      // Pad out the end with zero's if we need to.

      int chars = static_cast<int>(str.size());
      chars = digits - chars;

      if(scientific)
      {
        ++chars;
      }

      if(chars > 0)
      {
        str.append(static_cast<size_type>(chars), '0');
      }
    }

    if(fixed || (!scientific && (my_exp >= -4) && (my_exp < digits)))
    {
      if((1 + my_exp) > static_cast<int>(str.size()))
      {
        // Just pad out the end with zeros.
        str.append(static_cast<size_type>((1 + my_exp) - static_cast<int>(str.size())), '0');

        if(showpoint || fixed)
        {
          str.append(".");
        }
      }
      else if(my_exp + 1 < static_cast<int>(str.size()))
      {
        if(my_exp < 0)
        {
          str.insert(0U, static_cast<size_type>(-1 - my_exp), '0');
          str.insert(0U, "0.");
        }
        else
        {
          // Insert the decimal point:
          str.insert(static_cast<size_type>(my_exp + 1), 1, '.');
        }
      }
      else if(showpoint || fixed) // we have exactly the digits we require to left of the point
      {
        str += ".";
      }

      if(fixed)
      {
        // We may need to add trailing zeros.
        int l = static_cast<int>(str.find('.') + 1U);
        l = digits - (static_cast<int>(str.size()) - l);

        if(l > 0)
        {
          str.append(size_type(l), '0');
        }
      }
    }
    else
    {
      // Scientific format:
      if(showpoint || (str.size() > 1))
      {
        str.insert(1U, 1U, '.');
      }

      str.append(1U, 'e');
      string_type e = boost::lexical_cast<string_type>(std::abs(my_exp));

      if(e.size() < 2U)
      {
        e.insert(0U, 2U - e.size(), '0');
      }

      if(my_exp < 0)
      {
        e.insert(0U, 1U, '-');
      }
      else
      {
        e.insert(0U, 1U, '+');
      }

      str.append(e);
    }

    if(b_neg)
    {
      str.insert(0U, 1U, '-');
    }
    else if(showpos)
    {
      str.insert(0U, 1U, '+');
    }
  }

  template<class float_type, class type_a> inline void eval_convert_to(type_a* pa,    const float_type& cb)                        { *pa  = static_cast<type_a>(cb); }
  template<class float_type, class type_a> inline void eval_add       (float_type& b, const type_a& a)                             { b   += a; }
  template<class float_type, class type_a> inline void eval_subtract  (float_type& b, const type_a& a)                             { b   -= a; }
  template<class float_type, class type_a> inline void eval_multiply  (float_type& b, const type_a& a)                             { b   *= a; }
  template<class float_type>               inline void eval_multiply  (float_type& b, const float_type& cb, const float_type& cb2) { b    = (cb * cb2); }
  template<class float_type, class type_a> inline void eval_divide    (float_type& b, const type_a& a)                             { b   /= a; }
  template<class float_type>               inline void eval_log10     (float_type& b, const float_type& cb)                        { b    = std::log10(cb); }
  template<class float_type>               inline void eval_floor     (float_type& b, const float_type& cb)                        { b    = std::floor(cb); }

  inline void round_string_up_at(std::string& s, int pos, int& expon)
  {
    // This subroutine rounds up a string representation of a
    // number at the given position pos.

    if(pos < 0)
    {
      s.insert(0U, 1U, '1');
      s.erase(s.size() - 1U);
      ++expon;
    }
    else if(s[pos] == '9')
    {
      s[pos] = '0';
      round_string_up_at(s, pos - 1, expon);
    }
    else
    {
      if((pos == 0) && (s[pos] == '0') && (s.size() == 1))
      {
        ++expon;
      }

      ++s[pos];
    }
  }

  template<class float_type>
  std::string convert_to_string(float_type& x,
                                std::streamsize digits,
                                const std::ios_base::fmtflags f)
  {
    const bool isneg  = (x < 0);
    const bool iszero = ((!isneg) ? bool(+x < (std::numeric_limits<float_type>::min)())
                                  : bool(-x < (std::numeric_limits<float_type>::min)()));
    const bool isnan  = (x != x);
    const bool isinf  = ((!isneg) ? bool(+x > (std::numeric_limits<float_type>::max)())
                                  : bool(-x > (std::numeric_limits<float_type>::max)()));

    int expon = 0;

    if(digits <= 0) { digits = std::numeric_limits<float_type>::max_digits10; }

    const int org_digits = static_cast<int>(digits);

    std::string result;

    if(iszero)
    {
      result = "0";
    }
    else if(isinf)
    {
      if(x < 0)
      {
        return "-inf";
      }
      else
      {
        return ((f & std::ios_base::showpos) == std::ios_base::showpos) ? "+inf" : "inf";
      }
    }
    else if(isnan)
    {
      return "nan";
    }
    else
    {
      // Start by figuring out the base-10 exponent.
      if(isneg) { x = -x; }

      float_type t;
      float_type ten = 10;

      eval_log10(t, x);
      eval_floor(t, t);
      eval_convert_to(&expon, t);

      if(-expon > std::numeric_limits<float_type>::max_exponent10 - 3)
      {
        int e = -expon / 2;

        const float_type t2 = boost::math::cstdfloat::detail::pown(ten, e);

        eval_multiply(t, t2, x);
        eval_multiply(t, t2);

        if((expon & 1) != 0)
        {
          eval_multiply(t, ten);
        }
      }
      else
      {
        t = boost::math::cstdfloat::detail::pown(ten, -expon);
        eval_multiply(t, x);
      }

      // Make sure that the value lies between [1, 10), and adjust if not.
      if(t < 1)
      {
        eval_multiply(t, 10);

        --expon;
      }
      else if(t >= 10)
      {
        eval_divide(t, 10);

        ++expon;
      }

      float_type digit;
      int        cdigit;

      // Adjust the number of digits required based on formatting options.
      if(((f & std::ios_base::fixed) == std::ios_base::fixed) && (expon != -1))
      {
        digits += (expon + 1);
      }

      if((f & std::ios_base::scientific) == std::ios_base::scientific)
      {
        ++digits;
      }

      // Extract the base-10 digits one at a time.
      for(int i = 0; i < digits; ++i)
      {
        eval_floor(digit, t);
        eval_convert_to(&cdigit, digit);

        result += static_cast<char>('0' + cdigit);

        eval_subtract(t, digit);
        eval_multiply(t, ten);
      }

      // Possibly round the result.
      if(digits >= 0)
      {
        eval_floor(digit, t);
        eval_convert_to(&cdigit, digit);
        eval_subtract(t, digit);

        if((cdigit == 5) && (t == 0))
        {
          // Use simple bankers rounding.

          if((static_cast<int>(*result.rbegin() - '0') & 1) != 0)
          {
            round_string_up_at(result, static_cast<int>(result.size() - 1U), expon);
          }
        }
        else if(cdigit >= 5)
        {
          round_string_up_at(result, static_cast<int>(result.size() - 1), expon);
        }
      }
    }

    while((result.size() > static_cast<std::string::size_type>(digits)) && result.size())
    {
      // We may get here as a result of rounding.

      if(result.size() > 1U)
      {
        result.erase(result.size() - 1U);
      }
      else
      {
        if(expon > 0)
        {
          --expon; // so we put less padding in the result.
        }
        else
        {
          ++expon;
        }

        ++digits;
      }
    }

    if(isneg)
    {
      result.insert(0U, 1U, '-');
    }

    format_float_string(result, expon, org_digits, f, iszero);

    return result;
  }

  template <class float_type>
  bool convert_from_string(float_type& value, const char* p)
  {
    value = 0;

    if((p == static_cast<const char*>(0U)) || (*p == static_cast<char>(0)))
    {
      return;
    }

    bool is_neg       = false;
    bool is_neg_expon = false;

    BOOST_CONSTEXPR_OR_CONST int ten = 10;

    int expon       = 0;
    int digits_seen = 0;

    BOOST_CONSTEXPR_OR_CONST int max_digits = std::numeric_limits<float_type>::max_digits10 + 1;

    if(*p == static_cast<char>('+'))
    {
      ++p;
    }
    else if(*p == static_cast<char>('-'))
    {
      is_neg = true;
      ++p;
    }

    const bool isnan = ((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0));

    if(isnan)
    {
      eval_divide(value, 0);

      if(is_neg)
      {
        value = -value;
      }

      return true;
    }

    const bool isinf = ((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0));

    if(isinf)
    {
      value = 1;
      eval_divide(value, 0);

      if(is_neg)
      {
        value = -value;
      }

      return true;
    }

    // Grab all the leading digits before the decimal point.
    while(std::isdigit(*p))
    {
      eval_multiply(value, ten);
      eval_add(value, static_cast<int>(*p - '0'));
      ++p;
      ++digits_seen;
    }

    if(*p == static_cast<char>('.'))
    {
      // Grab everything after the point, stop when we've seen
      // enough digits, even if there are actually more available.

      ++p;

      while(std::isdigit(*p))
      {
        eval_multiply(value, ten);
        eval_add(value, static_cast<int>(*p - '0'));
        ++p;
        --expon;

        if(++digits_seen > max_digits)
        {
          break;
        }
      }

      while(std::isdigit(*p))
      {
        ++p;
      }
    }

    // Parse the exponent.
    if((*p == static_cast<char>('e')) || (*p == static_cast<char>('E')))
    {
      ++p;

      if(*p == static_cast<char>('+'))
      {
        ++p;
      }
      else if(*p == static_cast<char>('-'))
      {
        is_neg_expon = true;
        ++p;
      }

      int e2 = 0;

      while(std::isdigit(*p))
      {
        e2 *= 10;
        e2 += (*p - '0');
        ++p;
      }

      if(is_neg_expon)
      {
        e2 = -e2;
      }

      expon += e2;
    }

    if(expon)
    {
      // Scale by 10^expon. Note that 10^expon can be outside the range
      // of our number type, even though the result is within range.
      // If that looks likely, then split the calculation in two parts.
      float_type t;
      t = ten;

      if(expon > (std::numeric_limits<float_type>::min_exponent10 + 2))
      {
        t = boost::math::cstdfloat::detail::pown(t, expon);
        eval_multiply(value, t);
      }
      else
      {
        t = boost::math::cstdfloat::detail::pown(t, (expon + digits_seen + 1));
        eval_multiply(value, t);
        t = ten;
        t = boost::math::cstdfloat::detail::pown(t, (-digits_seen - 1));
        eval_multiply(value, t);
      }
    }

    if(is_neg)
    {
      value = -value;
    }

    return (*p == static_cast<char>(0));
  }
  } } } } // boost::math::cstdfloat::detail

  namespace std
  {
    template<typename char_type, class traits_type>
    inline std::basic_ostream<char_type, traits_type>& operator<<(std::basic_ostream<char_type, traits_type>& os, const boost::math::cstdfloat::detail::float_internal128_t& x)
    {
      boost::math::cstdfloat::detail::float_internal128_t non_const_x = x;

      const std::string str = boost::math::cstdfloat::detail::convert_to_string(non_const_x,
                                                                                os.precision(),
                                                                                os.flags());

      std::basic_ostringstream<char_type, traits_type> ostr;
      ostr.flags(os.flags());
      ostr.imbue(os.getloc());
      ostr.precision(os.precision());

      static_cast<void>(ostr << str);

      return (os << ostr.str());
    }

    template<typename char_type, class traits_type>
    inline std::basic_istream<char_type, traits_type>& operator>>(std::basic_istream<char_type, traits_type>& is, boost::math::cstdfloat::detail::float_internal128_t& x)
    {
      std::string str;

      static_cast<void>(is >> str);

      const bool conversion_is_ok = boost::math::cstdfloat::detail::convert_from_string(x, str.c_str());

      if(false == conversion_is_ok)
      {
        for(std::string::const_reverse_iterator it = str.rbegin(); it != str.rend(); ++it)
        {
          static_cast<void>(is.putback(*it));
        }

        is.setstate(ios_base::failbit);

        BOOST_THROW_EXCEPTION(std::runtime_error("Unable to interpret input string as a boost::float128_t"));
      }

      return is;
    }
  }

  #endif // Use __GNUC__ or BOOST_INTEL libquadmath

  #endif // Not BOOST_CSTDFLOAT_NO_LIBQUADMATH_SUPPORT (i.e., the user would like to have libquadmath support)

#endif // BOOST_MATH_CSTDFLOAT_IOSTREAM_2014_02_15_HPP_

max_stars_repo_name: kindlychung/mediasoup-sfu-cpp

max_issues_repo_name: kindlychung/mediasoup-sfu-cpp

max_forks_repo_name: kindlychung/mediasoup-sfu-cpp


text:
/*

Copyright (c) 2005-2018, University of Oxford.
All rights reserved.

University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.

This file is part of Chaste.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
 * Neither the name of the University of Oxford nor the names of its
   contributors may be used to endorse or promote products derived from this
   software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TESTCYLINDRICAL2DVERTEXMESH_HPP_
#define TESTCYLINDRICAL2DVERTEXMESH_HPP_

#include <cxxtest/TestSuite.h>

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include "CylindricalHoneycombVertexMeshGenerator.hpp"
#include "Cylindrical2dVertexMesh.hpp"

#include "CylindricalHoneycombMeshGenerator.hpp"
#include "Cylindrical2dMesh.hpp"
#include "TrianglesMeshWriter.hpp"

#include "VertexMeshWriter.hpp"
#include "ArchiveOpener.hpp"
//This test is always run sequentially (never in parallel)
#include "FakePetscSetup.hpp"

class TestCylindrical2dVertexMesh : public CxxTest::TestSuite
{
public:

    void TestEachNodeIsContainedInAtLeastOneElement()
    {
        // Create mesh
        CylindricalHoneycombVertexMeshGenerator generator(18, 25, true);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        for (unsigned node_index=0; node_index<p_mesh->GetNumNodes(); node_index++)
        {
            std::set<unsigned> containing_elements = p_mesh->GetNode(node_index)->rGetContainingElementIndices();
            unsigned num_containing_elements = containing_elements.size();

            TS_ASSERT_LESS_THAN(0u, num_containing_elements);
        }
    }

    void TestMeshGetWidth()
    {
        // Create mesh
        CylindricalHoneycombVertexMeshGenerator generator(4, 4);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        // Test CalculateBoundingBox() method
        ChasteCuboid<2> bounds = p_mesh->CalculateBoundingBox();

        ///\todo this should really be 4 as mesh is periodic
        TS_ASSERT_DELTA(bounds.rGetUpperCorner()[0], 3.5, 1e-4);

        TS_ASSERT_DELTA(bounds.rGetUpperCorner()[1], 13.0*0.5/sqrt(3.0), 1e-4);
        TS_ASSERT_DELTA(bounds.rGetLowerCorner()[0], 0.0, 1e-4);
        TS_ASSERT_DELTA(bounds.rGetLowerCorner()[1], 0.0, 1e-4);

        // Test GetWidth() method
        double width = p_mesh->GetWidth(0);
        double height = p_mesh->GetWidth(1);

        TS_ASSERT_DELTA(width, 4, 1e-4);
        TS_ASSERT_DELTA(height, 13.0*0.5/sqrt(3.0), 1e-4);

        //Scale mesh and check its updated correctly
        p_mesh->Scale(0.5,1.0);
        TS_ASSERT_DELTA(p_mesh->GetWidth(0), 2, 1e-4);
    }

    void TestGetVectorFromAtoB()
    {
        // Create mesh
        CylindricalHoneycombVertexMeshGenerator generator(4, 4);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        c_vector<double, 2> node18_location = p_mesh->GetNode(18)->rGetLocation();
        c_vector<double, 2> node19_location = p_mesh->GetNode(19)->rGetLocation();

        // Test a normal vector and distance calculation
        c_vector<double, 2> vector = p_mesh->GetVectorFromAtoB(node18_location, node19_location);
        TS_ASSERT_DELTA(vector[0], 1.0, 1e-4);
        TS_ASSERT_DELTA(vector[1], 0.0000, 1e-4);
        TS_ASSERT_DELTA(norm_2(vector), 1.0, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetDistanceBetweenNodes(18, 19), 1.0, 1e-4);

        // Test the opposite vector
        vector = p_mesh->GetVectorFromAtoB(node19_location, node18_location);
        TS_ASSERT_DELTA(vector[0], -1.0, 1e-4);
        TS_ASSERT_DELTA(vector[1], 0.0000, 1e-4);

        // Test a periodic calculation
        c_vector<double, 2> node16_location = p_mesh->GetNode(16)->rGetLocation();
        vector = p_mesh->GetVectorFromAtoB(node16_location, node19_location);

        TS_ASSERT_DELTA(vector[0], -1.0, 1e-4);
        TS_ASSERT_DELTA(vector[1], 0.0000, 1e-4);
    }

    void TestSetNodeLocationForCylindricalMesh()
    {
        // Create mesh
        CylindricalHoneycombVertexMeshGenerator generator(4, 4);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        // Move one of the nodes to near the periodic boundary
        c_vector<double, 2> new_point_location;
        new_point_location[0] = -0.01;
        new_point_location[1] = 3.0*0.5/sqrt(3.0);
        ChastePoint<2> new_point(new_point_location);

        // This node was on left and is now near the right
        p_mesh->SetNode(12, new_point);
        TS_ASSERT_DELTA(p_mesh->GetNode(12)->rGetLocation()[0], 3.99, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetNode(12)->rGetLocation()[1], 3.0*0.5/sqrt(3.0), 1e-4);

        // This node has stayed close to where it was
        new_point.SetCoordinate(0, 0.2);
        p_mesh->SetNode(0, new_point);
        TS_ASSERT_DELTA(p_mesh->GetNode(0)->rGetLocation()[0], 0.2, 1e-4);

        // This node was on right and is now near the left
        new_point.SetCoordinate(0, 4.1);
        p_mesh->SetNode(8, new_point);
        TS_ASSERT_DELTA(p_mesh->GetNode(8)->rGetLocation()[0], 0.1, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetNode(8)->rGetLocation()[1], 3.0*0.5/sqrt(3.0), 1e-4);
    }

    void TestAddNodeAndReMesh()
    {
        // Create mesh
        CylindricalHoneycombVertexMeshGenerator generator(6, 6);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 84u);
        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 36u);

        // Choose a node on the left boundary
        ChastePoint<2> point = p_mesh->GetNode(18)->GetPoint();
        TS_ASSERT_DELTA(point[0], 0.5, 1e-4);
        TS_ASSERT_DELTA(point[1], 4.0*0.5/sqrt(3.0), 1e-4);

        // Create a new node close to this node
        point.SetCoordinate(0, -0.01);
        point.SetCoordinate(1, 4.5);
        Node<2>* p_node = new Node<2>(p_mesh->GetNumNodes(), point);

        unsigned old_num_nodes = p_mesh->GetNumNodes();

        // Add this new node to the mesh
        unsigned new_index = p_mesh->AddNode(p_node);
        TS_ASSERT_EQUALS(new_index, old_num_nodes);

        // Remesh to update correspondences
        VertexElementMap map(p_mesh->GetNumElements());
        p_mesh->ReMesh(map);

        TS_ASSERT_EQUALS(map.Size(), p_mesh->GetNumElements());
        TS_ASSERT_EQUALS(map.IsIdentityMap(), true);

        // Check that the mesh is updated
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 85u);
        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 36u);

        TS_ASSERT_DELTA(p_mesh->GetNode(new_index)->rGetLocation()[0], 5.99, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetNode(new_index)->rGetLocation()[1], 4.5000, 1e-4);

        // Now test AddNode() when mDeletedNodeIndices is populated

        // Label node 29 as deleted
        p_mesh->mDeletedNodeIndices.push_back(29);

        // Create a new node close to this node
        ChastePoint<2> point2;
        point2.SetCoordinate(0, 2.0);
        point2.SetCoordinate(1, 2.1);
        Node<2>* p_node2 = new Node<2>(p_mesh->GetNumNodes(), point);

        // Add this new node to the mesh
        new_index = p_mesh->AddNode(p_node2);
        TS_ASSERT_EQUALS(new_index, 29u);
    }

    void TestElementAreaPerimeterCentroidAndMoments()
    {
        // Test methods with a regular cylindrical honeycomb mesh
        CylindricalHoneycombVertexMeshGenerator generator(4, 4);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 40u);

        // Test area and perimeter calculations for all elements
        for (unsigned i=0; i<p_mesh->GetNumElements(); i++)
        {
            TS_ASSERT_DELTA(p_mesh->GetVolumeOfElement(i), 0.8660, 1e-4);
            TS_ASSERT_DELTA(p_mesh->GetSurfaceAreaOfElement(i), 3.4641, 1e-4);
        }

        // Test centroid calculations for non-periodic element
        c_vector<double, 2> centroid = p_mesh->GetCentroidOfElement(5);
        TS_ASSERT_DELTA(centroid(0), 2.0, 1e-4);
        TS_ASSERT_DELTA(centroid(1), 5.0*0.5/sqrt(3.0), 1e-4);

        // Test centroid calculations for periodic element
        centroid = p_mesh->GetCentroidOfElement(7);
        TS_ASSERT_DELTA(centroid(0), 0.0, 1e-4);
        TS_ASSERT_DELTA(centroid(1), 5.0*0.5/sqrt(3.0), 1e-4);

        // Test CalculateMomentOfElement() for all elements
        // all elements are regular hexagons with edge 1/sqrt(3.0)
        c_vector<double, 3> moments;
        for (unsigned i=0; i<p_mesh->GetNumElements(); i++)
        {
            moments = p_mesh->CalculateMomentsOfElement(i);

            TS_ASSERT_DELTA(moments(0), 5*sqrt(3.0)/16/9, 1e-6); // Ixx
            TS_ASSERT_DELTA(moments(1), 5*sqrt(3.0)/16/9, 1e-6); // Iyy
            TS_ASSERT_DELTA(moments(2), 0.0, 1e-6);            // Ixy = 0 by symmetry
        }

        // Test methods with a cylindrical mesh comprising a single rectangular element
        std::vector<Node<2>*> rectangle_nodes;
        rectangle_nodes.push_back(new Node<2>(0, false, 8.0, 2.0));
        rectangle_nodes.push_back(new Node<2>(1, false, 8.0, 0.0));
        rectangle_nodes.push_back(new Node<2>(2, false, 2.0, 0.0));
        rectangle_nodes.push_back(new Node<2>(3, false, 2.0, 2.0));
        std::vector<VertexElement<2,2>*> rectangle_elements;
        rectangle_elements.push_back(new VertexElement<2,2>(0, rectangle_nodes));

        Cylindrical2dVertexMesh rectangle_mesh(10.0, rectangle_nodes, rectangle_elements);

        TS_ASSERT_DELTA(rectangle_mesh.GetVolumeOfElement(0), 8.0, 1e-10);
        TS_ASSERT_DELTA(rectangle_mesh.GetSurfaceAreaOfElement(0), 12.0, 1e-4);

        ///\todo #2393 - for consistency, the centroid should be at (0, 2.5)
        c_vector<double, 2> rectangle_centroid = rectangle_mesh.GetCentroidOfElement(0);
        TS_ASSERT_DELTA(rectangle_centroid(0), 10.0, 1e-4);
        TS_ASSERT_DELTA(rectangle_centroid(1), 1.0, 1e-4);

        c_vector<double, 3> rectangle_moments = rectangle_mesh.CalculateMomentsOfElement(0);
        TS_ASSERT_DELTA(rectangle_moments(0), 8.0/3.0, 1e-6);  // Ixx
        TS_ASSERT_DELTA(rectangle_moments(1), 32.0/3.0, 1e-6); // Iyy
        TS_ASSERT_DELTA(rectangle_moments(2), 0.0, 1e-6);      // Ixy = 0 by symmetry

        c_vector<double, 2> rectangle_short_axis = rectangle_mesh.GetShortAxisOfElement(0);
        TS_ASSERT_DELTA(rectangle_short_axis(0), 0.0, 1e-4);
        TS_ASSERT_DELTA(rectangle_short_axis(1), 1.0, 1e-4);
    }

    void TestDivideElementAlongGivenAxis()
    {
        // Create mesh
        CylindricalHoneycombVertexMeshGenerator generator(4, 4);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 16u);
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 40u);

        c_vector<double, 2> axis_of_division;
        axis_of_division(0) = 1.0/sqrt(2.0);
        axis_of_division(1) = 1.0/sqrt(2.0);

        // Divide non-periodic element
        unsigned new_element_index = p_mesh->DivideElementAlongGivenAxis(p_mesh->GetElement(2), axis_of_division, true);

        TS_ASSERT_EQUALS(new_element_index, 16u);
        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 17u);
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 42u);

        TS_ASSERT_DELTA(p_mesh->GetNode(40)->rGetLocation()[0], 2.8660, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetNode(40)->rGetLocation()[1], 0.9433, 1e-4);

        TS_ASSERT_DELTA(p_mesh->GetNode(41)->rGetLocation()[0], 2.1339, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetNode(41)->rGetLocation()[1], 0.2113, 1e-4);

        // Test new elements have correct nodes
        TS_ASSERT_EQUALS(p_mesh->GetElement(2)->GetNumNodes(), 5u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(2)->GetNode(0)->GetIndex(), 2u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(2)->GetNode(1)->GetIndex(), 7u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(2)->GetNode(2)->GetIndex(), 11u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(2)->GetNode(3)->GetIndex(), 40u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(2)->GetNode(4)->GetIndex(), 41u);

        TS_ASSERT_EQUALS(p_mesh->GetElement(16)->GetNumNodes(), 5u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(16)->GetNode(0)->GetIndex(), 40u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(16)->GetNode(1)->GetIndex(), 14u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(16)->GetNode(2)->GetIndex(), 10u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(16)->GetNode(3)->GetIndex(), 6u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(16)->GetNode(4)->GetIndex(), 41u);

        // Divide periodic element
        new_element_index = p_mesh->DivideElementAlongGivenAxis(p_mesh->GetElement(3), axis_of_division, true);

        TS_ASSERT_EQUALS(new_element_index, 17u);
        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 18u);
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 44u);

        TS_ASSERT_DELTA(p_mesh->GetNode(42)->rGetLocation()[0], -0.1339, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetNode(42)->rGetLocation()[1], 0.9433, 1e-4);

        TS_ASSERT_DELTA(p_mesh->GetNode(43)->rGetLocation()[0], 3.1339, 1e-4);
        TS_ASSERT_DELTA(p_mesh->GetNode(43)->rGetLocation()[1], 0.2113, 1e-4);

        // Test new elements have correct nodes
        TS_ASSERT_EQUALS(p_mesh->GetElement(3)->GetNumNodes(), 5u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(3)->GetNode(0)->GetIndex(), 3u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(3)->GetNode(1)->GetIndex(), 4u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(3)->GetNode(2)->GetIndex(), 8u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(3)->GetNode(3)->GetIndex(), 42u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(3)->GetNode(4)->GetIndex(), 43u);

        TS_ASSERT_EQUALS(p_mesh->GetElement(17)->GetNumNodes(), 5u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(17)->GetNode(0)->GetIndex(), 42u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(17)->GetNode(1)->GetIndex(), 15u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(17)->GetNode(2)->GetIndex(), 11u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(17)->GetNode(3)->GetIndex(), 7u);
        TS_ASSERT_EQUALS(p_mesh->GetElement(17)->GetNode(4)->GetIndex(), 43u);
    }

    void TestTessellationConstructor()
    {
        // Create a simple Cylindrical2dMesh, the Delaunay triangulation
        unsigned cells_across = 3;
        unsigned cells_up = 3;
        unsigned thickness_of_ghost_layer = 0;
        CylindricalHoneycombMeshGenerator generator(cells_across, cells_up, thickness_of_ghost_layer);
        Cylindrical2dMesh* p_delaunay_mesh = generator.GetCylindricalMesh();

        TrianglesMeshWriter<2,2> mesh_writer("TestVertexMeshWriters", "DelaunayMesh", false);
        TS_ASSERT_THROWS_NOTHING(mesh_writer.WriteFilesUsingMesh(*p_delaunay_mesh));

        TS_ASSERT_EQUALS(p_delaunay_mesh->GetWidth(0), 3u);
        TS_ASSERT_EQUALS(p_delaunay_mesh->CheckIsVoronoi(), true);
        TS_ASSERT_EQUALS(p_delaunay_mesh->GetNumElements(), 12u);
        TS_ASSERT_EQUALS(p_delaunay_mesh->GetNumNodes(), 9u);

        // Create a vertex mesh, the Voronoi tessellation, using the tetrahedral mesh
        Cylindrical2dVertexMesh voronoi_mesh(*p_delaunay_mesh);

        VertexMeshWriter<2,2> vertexmesh_writer("TestVertexMeshWriters", "VertexMesh", false);
        TS_ASSERT_THROWS_NOTHING(vertexmesh_writer.WriteFilesUsingMesh(voronoi_mesh));

        // Test the Voronoi tessellation has the correct number of nodes and elements
        TS_ASSERT_EQUALS(voronoi_mesh.GetWidth(0), 3u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetNumElements(), 9u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetNumNodes(), 12u);
//
        // Test the location of the Voronoi nodes
        /* These are ordered from right to left from bottom to top as
         * 10 1 0 5 4 6 9 2 3 11 7 8
         * Due to the numbering of the elements in the generator.
         */
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(10)->rGetLocation()[0], 3.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(10)->rGetLocation()[1], sqrt(3.0)/3.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(1)->rGetLocation()[0], 0.5, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(1)->rGetLocation()[1], sqrt(3.0)/6.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(0)->rGetLocation()[0], 1.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(0)->rGetLocation()[1], sqrt(3.0)/3.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(5)->rGetLocation()[0], 1.5, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(5)->rGetLocation()[1], sqrt(3.0)/6.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(4)->rGetLocation()[0], 2.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(4)->rGetLocation()[1], sqrt(3.0)/3.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(6)->rGetLocation()[0], 2.5, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(6)->rGetLocation()[1], sqrt(3.0)/6.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(9)->rGetLocation()[0], 0.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(9)->rGetLocation()[1], 2.0*sqrt(3.0)/3.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(2)->rGetLocation()[0], 0.5, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(2)->rGetLocation()[1], 5.0*sqrt(3.0)/6.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(3)->rGetLocation()[0], 1.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(3)->rGetLocation()[1], 2.0*sqrt(3.0)/3.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(11)->rGetLocation()[0], 1.5, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(11)->rGetLocation()[1], 5.0*sqrt(3.0)/6.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(7)->rGetLocation()[0], 2.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(7)->rGetLocation()[1], 2.0*sqrt(3.0)/3.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(8)->rGetLocation()[0], 2.5, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetNode(8)->rGetLocation()[1], 5.0*sqrt(3.0)/6.0, 1e-6);

        // Test the number of nodes owned by each Voronoi element
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(0)->GetNumNodes(), 3u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(1)->GetNumNodes(), 3u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(2)->GetNumNodes(), 3u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(3)->GetNumNodes(), 6u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(4)->GetNumNodes(), 6u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(5)->GetNumNodes(), 6u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(6)->GetNumNodes(), 3u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(7)->GetNumNodes(), 3u);
        TS_ASSERT_EQUALS(voronoi_mesh.GetElement(8)->GetNumNodes(), 3u);

        // Test element areas
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(0), sqrt(3.0)/12.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(1), sqrt(3.0)/12.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(2), sqrt(3.0)/12.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(3), sqrt(3.0)/2.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(4), sqrt(3.0)/2.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(5), sqrt(3.0)/2.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(6), sqrt(3.0)/12.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(7), sqrt(3.0)/12.0, 1e-6);
        TS_ASSERT_DELTA(voronoi_mesh.GetVolumeOfElement(8), sqrt(3.0)/12.0, 1e-6);
    }

    void TestArchiving()
    {
        FileFinder archive_dir("archive", RelativeTo::ChasteTestOutput);
        std::string archive_file = "cylindrical_vertex_mesh_base.arch";
        ArchiveLocationInfo::SetMeshFilename("cylindrical_vertex_mesh");

        // Create mesh
        unsigned num_cells_across = 4;
        unsigned num_cells_up = 7;
        CylindricalHoneycombVertexMeshGenerator generator(num_cells_across, num_cells_up);
        AbstractMesh<2,2>* const p_saved_mesh = generator.GetCylindricalMesh();

        double crypt_width = num_cells_across;

        /*
         * You need the const above to stop a BOOST_STATIC_ASSERTION failure.
         * This is because the serialization library only allows you to save
         * tracked objects while the compiler considers them const, to prevent
         * the objects changing during the save, and so object tracking leading
         * to wrong results. For example, A is saved once via pointer, then
         * changed, then saved again.  The second save notes that A was saved
         * before, so doesn't write its data again, and the change is lost.
         */
        {
            // Serialize the mesh
            TS_ASSERT_DELTA((static_cast<Cylindrical2dVertexMesh*>(p_saved_mesh))->GetWidth(0), crypt_width, 1e-7);

            // Create output archive
            ArchiveOpener<boost::archive::text_oarchive, std::ofstream> arch_opener(archive_dir, archive_file);
            boost::archive::text_oarchive* p_arch = arch_opener.GetCommonArchive();

            // We have to serialize via a pointer here, or the derived class information is lost.
            (*p_arch) << p_saved_mesh;
        }

        {
            // De-serialize and compare
            AbstractMesh<2,2>* p_loaded_mesh;

            // Create an input archive
            ArchiveOpener<boost::archive::text_iarchive, std::ifstream> arch_opener(archive_dir, archive_file);
            boost::archive::text_iarchive* p_arch = arch_opener.GetCommonArchive();

            // Restore from the archive
            (*p_arch) >> p_loaded_mesh;

            // Compare the loaded mesh against the original
            Cylindrical2dVertexMesh* p_mesh2 = static_cast<Cylindrical2dVertexMesh*>(p_loaded_mesh);
            Cylindrical2dVertexMesh* p_mesh = static_cast<Cylindrical2dVertexMesh*>(p_saved_mesh);

            // Compare width
            TS_ASSERT_DELTA(p_mesh2->GetWidth(0), crypt_width, 1e-7);
            TS_ASSERT_DELTA(p_mesh->GetWidth(0), crypt_width, 1e-7);

            // Compare nodes
            TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), p_mesh2->GetNumNodes());

            for (unsigned i=0; i<p_mesh->GetNumNodes(); i++)
            {
                Node<2>* p_node = p_mesh->GetNode(i);
                Node<2>* p_node2 = p_mesh2->GetNode(i);
                TS_ASSERT_EQUALS(p_node->IsDeleted(), p_node2->IsDeleted());
                TS_ASSERT_EQUALS(p_node->GetIndex(), p_node2->GetIndex());

                TS_ASSERT_EQUALS(p_node->IsBoundaryNode(), p_node2->IsBoundaryNode());
                for (unsigned j=0; j<2; j++)
                {
                    TS_ASSERT_DELTA(p_node->rGetLocation()[j], p_node2->rGetLocation()[j], 1e-4);
                }
            }

            // Compare elements
            TS_ASSERT_EQUALS(p_mesh->GetNumElements(), p_mesh2->GetNumElements());
            TS_ASSERT_EQUALS(p_mesh->GetNumAllElements(), p_mesh2->GetNumAllElements());

            for (unsigned i=0; i<p_mesh->GetNumElements(); i++)
            {
                VertexElement<2,2>* p_elt = p_mesh->GetElement(i);
                VertexElement<2,2>* p_elt2 = p_mesh2->GetElement(i);
                TS_ASSERT_EQUALS(p_elt->GetNumNodes(), p_elt2->GetNumNodes());
                for (unsigned j=0; j<p_elt->GetNumNodes(); j++)
                {
                    TS_ASSERT_EQUALS(p_elt->GetNodeGlobalIndex(j), p_elt2->GetNodeGlobalIndex(j));
                }
            }

            // Tidy up
            delete p_mesh2;
        }
    }

    void TestCylindricalReMesh()
    {
        // Create mesh
        unsigned num_cells_across = 6;
        unsigned num_cells_up = 12;
        CylindricalHoneycombVertexMeshGenerator generator(num_cells_across, num_cells_up);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        // Remesh
        VertexElementMap map(p_mesh->GetNumElements());
        p_mesh->ReMesh(map);

        TS_ASSERT_EQUALS(map.Size(), p_mesh->GetNumElements());
        TS_ASSERT_EQUALS(map.IsIdentityMap(), true);

        // Check that there are the correct number of elements
        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), num_cells_across*num_cells_up);
    }

    void TestCylindricalReMeshAfterDelete()
    {
        // Create mesh
        unsigned num_cells_across = 6;
        unsigned num_cells_up = 12;
        CylindricalHoneycombVertexMeshGenerator generator(num_cells_across, num_cells_up);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        unsigned num_old_nodes = p_mesh->GetNumNodes();
        unsigned num_old_elements = num_cells_across*num_cells_up;

        // Delete a node
        p_mesh->DeleteElementPriorToReMesh(8);

        // Remesh
        VertexElementMap map(p_mesh->GetNumElements());
        p_mesh->ReMesh(map);

        TS_ASSERT_EQUALS(map.IsIdentityMap(), false);
        TS_ASSERT_EQUALS(map.Size(), num_old_elements);

        // Check that there are the correct number of elements and nodes
        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), num_old_nodes);
        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), num_old_elements-1);
    }

    void TestCylindricalElementIncludesPointAndGetLocalIndexForElementEdgeClosestToPoint()
    {
        // Create a cylindrical mesh comprising a single rectangular element
        std::vector<Node<2>*> nodes;
        nodes.push_back(new Node<2>(0, false, 9.0, 2.0));
        nodes.push_back(new Node<2>(1, false, 9.0, 0.0));
        nodes.push_back(new Node<2>(2, false, 1.0, 0.0));
        nodes.push_back(new Node<2>(3, false, 1.0, 2.0));
        std::vector<VertexElement<2,2>*> elements;
        elements.push_back(new VertexElement<2,2>(0, nodes));

        Cylindrical2dVertexMesh mesh(10.0, nodes, elements);

        // Make some test points and test ElementIncludesPoint()

        // A point far outside the element
        c_vector<double, 2> test_point1;
        test_point1[0] = -1.0;
        test_point1[1] = -1.0;

        TS_ASSERT_EQUALS(mesh.ElementIncludesPoint(test_point1, 0), false);

        // A point outside the element due to periodicity
        c_vector<double, 2> test_point2;
        test_point1[0] = 3.0;
        test_point1[1] = 1.0;

        TS_ASSERT_EQUALS(mesh.ElementIncludesPoint(test_point1, 0), false);

        // A point far inside the element
        c_vector<double, 2> test_point3;
        test_point3[0] = 9.5;
        test_point3[1] = 1.0;

        TS_ASSERT_EQUALS(mesh.ElementIncludesPoint(test_point3, 0), true);
        TS_ASSERT_EQUALS(mesh.GetLocalIndexForElementEdgeClosestToPoint(test_point3, 0), 0u);

        // A point far inside the element as periodic
        c_vector<double, 2> test_point4;
        test_point4[0] = 0.5;
        test_point4[1] = 1.0;

        TS_ASSERT_EQUALS(mesh.ElementIncludesPoint(test_point4, 0), true);
        TS_ASSERT_EQUALS(mesh.GetLocalIndexForElementEdgeClosestToPoint(test_point4, 0), 2u);
    }

    void TestGetMeshForVtk()
    {
        // Create mesh
        CylindricalHoneycombVertexMeshGenerator generator(4, 4);
        Cylindrical2dVertexMesh* p_mesh = generator.GetCylindricalMesh();

        TS_ASSERT_EQUALS(p_mesh->GetNumNodes(), 40u);
        TS_ASSERT_EQUALS(p_mesh->GetNumElements(), 16u);

        // Test GetMeshForVtk() method
        VertexMesh<2, 2>* p_mesh_for_vtk = p_mesh->GetMeshForVtk();

        // The mesh for VTK should have the same number of elements, but 16 extra nodes
        TS_ASSERT_EQUALS(p_mesh_for_vtk->GetNumElements(), 16u);
        TS_ASSERT_EQUALS(p_mesh_for_vtk->GetNumNodes(), 48u);

        // Every element in the mesh for VTK should have 6 nodes
        for (unsigned elem_index=0; elem_index<p_mesh_for_vtk->GetNumElements(); elem_index++)
        {
            TS_ASSERT_EQUALS(p_mesh_for_vtk->GetElement(elem_index)->GetNumNodes(), 6u);
        }

        VertexElement<2, 2>* p_element0 = p_mesh_for_vtk->GetElement(0);
        TS_ASSERT_EQUALS(p_element0->GetNodeGlobalIndex(0), 0u);
        TS_ASSERT_EQUALS(p_element0->GetNodeGlobalIndex(1), 5u);
        TS_ASSERT_EQUALS(p_element0->GetNodeGlobalIndex(2), 9u);
        TS_ASSERT_EQUALS(p_element0->GetNodeGlobalIndex(3), 12u);
        TS_ASSERT_EQUALS(p_element0->GetNodeGlobalIndex(4), 8u);
        TS_ASSERT_EQUALS(p_element0->GetNodeGlobalIndex(5), 4u);

        VertexElement<2, 2>* p_element3 = p_mesh_for_vtk->GetElement(3);
        TS_ASSERT_EQUALS(p_element3->GetNodeGlobalIndex(0), 3u);
        TS_ASSERT_EQUALS(p_element3->GetNodeGlobalIndex(1), 39u);
        TS_ASSERT_EQUALS(p_element3->GetNodeGlobalIndex(2), 40u);
        TS_ASSERT_EQUALS(p_element3->GetNodeGlobalIndex(3), 15u);
        TS_ASSERT_EQUALS(p_element3->GetNodeGlobalIndex(4), 11u);
        TS_ASSERT_EQUALS(p_element3->GetNodeGlobalIndex(5), 7u);

        VertexElement<2, 2>* p_element7 = p_mesh_for_vtk->GetElement(7);
        TS_ASSERT_EQUALS(p_element7->GetNodeGlobalIndex(0), 40u);
        TS_ASSERT_EQUALS(p_element7->GetNodeGlobalIndex(1), 41u);
        TS_ASSERT_EQUALS(p_element7->GetNodeGlobalIndex(2), 42u);
        TS_ASSERT_EQUALS(p_element7->GetNodeGlobalIndex(3), 43u);
        TS_ASSERT_EQUALS(p_element7->GetNodeGlobalIndex(4), 19u);
        TS_ASSERT_EQUALS(p_element7->GetNodeGlobalIndex(5), 15u);

        VertexElement<2, 2>* p_element12 = p_mesh_for_vtk->GetElement(12);
        TS_ASSERT_EQUALS(p_element12->GetNodeGlobalIndex(0), 25u);
        TS_ASSERT_EQUALS(p_element12->GetNodeGlobalIndex(1), 29u);
        TS_ASSERT_EQUALS(p_element12->GetNodeGlobalIndex(2), 33u);
        TS_ASSERT_EQUALS(p_element12->GetNodeGlobalIndex(3), 36u);
        TS_ASSERT_EQUALS(p_element12->GetNodeGlobalIndex(4), 32u);
        TS_ASSERT_EQUALS(p_element12->GetNodeGlobalIndex(5), 28u);

        VertexElement<2, 2>* p_element15 = p_mesh_for_vtk->GetElement(15);
        TS_ASSERT_EQUALS(p_element15->GetNodeGlobalIndex(0), 44u);
        TS_ASSERT_EQUALS(p_element15->GetNodeGlobalIndex(1), 45u);
        TS_ASSERT_EQUALS(p_element15->GetNodeGlobalIndex(2), 46u);
        TS_ASSERT_EQUALS(p_element15->GetNodeGlobalIndex(3), 47u);
        TS_ASSERT_EQUALS(p_element15->GetNodeGlobalIndex(4), 35u);
        TS_ASSERT_EQUALS(p_element15->GetNodeGlobalIndex(5), 31u);
    }
};

#endif /*TESTCYLINDRICAL2DVERTEXMESH_HPP_*/

ext: hpp


text:
/* (c) 2016, 2021 FFF Services. For details refers to LICENSE.txt */
/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <graphene/chain/transfer_evaluator.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/account_object.hpp>
#include <graphene/chain/content_object.hpp>
#include <graphene/chain/transaction_detail_object.hpp>
#include <graphene/chain/database.hpp>
#include <graphene/chain/hardfork.hpp>

#include <boost/multiprecision/cpp_int.hpp>

namespace graphene { namespace chain {
operation_result transfer_obsolete_evaluator::do_evaluate( const operation_type& op )
{ try {
   const database& d = db();

   const account_object& from_account    = op.from(d);
   const account_object& to_account      = op.to(d);
   const asset_object&   asset_type      = op.amount.asset_id(d);

   try {

      bool sufficient_balance = d.get_balance( from_account, asset_type ).amount >= op.amount.amount;
      FC_ASSERT( sufficient_balance,
                 "Insufficient Balance: ${balance}, unable to transfer '${total_transfer}' from account '${a}' to '${t}'",
                 ("a",from_account.name)("t",to_account.name)("total_transfer",d.to_pretty_string(op.amount))("balance",d.to_pretty_string(d.get_balance(from_account, asset_type))) );

      return void_result();
   } FC_RETHROW_EXCEPTIONS( error, "Unable to transfer ${a} from ${f} to ${t}", ("a",d.to_pretty_string(op.amount))("f",op.from(d).name)("t",op.to(d).name) );

}  FC_CAPTURE_AND_RETHROW( (op) ) }

operation_result transfer_obsolete_evaluator::do_apply( const operation_type& o )
{ try {
   db().adjust_balance( o.from, -o.amount );
   db().adjust_balance( o.to, o.amount );

   auto & d = db();

   db().create<transaction_detail_object>([&o, &d](transaction_detail_object& obj)
                                          {
                                             obj.m_operation_type = (uint8_t)transaction_detail_object::transfer;

                                             obj.m_from_account = o.from;
                                             obj.m_to_account = o.to;
                                             obj.m_transaction_amount = o.amount;
                                             obj.m_transaction_fee = o.fee;
                                             obj.m_transaction_encrypted_memo = o.memo;
                                             obj.m_str_description = "transfer";
                                             obj.m_timestamp = d.head_block_time();
                                          });
   return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }

operation_result transfer_evaluator::do_evaluate( const operation_type& op )
{ try {
      const database& d = db();

      FC_ASSERT(db().head_block_time() > HARDFORK_2_TIME );
      const account_object& from_account        = op.from(d);
      const asset_object&   asset_type          = op.amount.asset_id(d);

      std::string to_account_name;
      if( op.to.is<content_id_type>() )
      {
         auto& content_idx = d.get_index_type<content_index>().indices().get<graphene::db::by_id>();
         const auto& content_itr = content_idx.find( op.to );
         FC_ASSERT( content_itr != content_idx.end(), "Content does not exist." );
         to_account_name = content_itr->author(d).name;
      }
      else if (db().head_block_time() > fc::time_point_sec( 1561543200 ))
      {
         // check only after block 12437308 because it contains transfer to non existing account
         const account_object& to_account = op.to.as<account_id_type>()(d);
         to_account_name = to_account.name;
      }

      try {
         bool sufficient_balance = d.get_balance( from_account, asset_type ).amount >= op.amount.amount;
         if (db().head_block_time() > fc::time_point_sec( 1561543200 ))
         {
            FC_ASSERT( sufficient_balance,
                       "Insufficient Balance: ${balance}, unable to transfer '${total_transfer}' from account '${a}' to '${t}'",
                       ("a",from_account.name)("t",to_account_name)("total_transfer",d.to_pretty_string(op.amount))("balance",d.to_pretty_string(d.get_balance(from_account, asset_type))) );
         }
         else
         {
            FC_ASSERT( sufficient_balance,
                       "Insufficient Balance: ${balance}, unable to transfer '${total_transfer}' from account '${a}' to '${t}'",
                       ("a",from_account.name)("t",op.to)("total_transfer",d.to_pretty_string(op.amount))("balance",d.to_pretty_string(d.get_balance(from_account, asset_type))) );
         }

         return void_result();
      } FC_RETHROW_EXCEPTIONS( error, "Unable to transfer ${a} from ${f} to ${t}", ("a",d.to_pretty_string(op.amount))("f",op.from(d).name)("t",op.to) );

   }  FC_CAPTURE_AND_RETHROW( (op) ) }

operation_result transfer_evaluator::do_apply( const operation_type& o )
{ try {
      auto & d = db();
      account_id_type to_acc;

      d.adjust_balance( o.from, -o.amount );
      std::string suffix;

      if( o.to.is<account_id_type>() )
      {
         to_acc = o.to.as<account_id_type>();
         d.adjust_balance( to_acc, o.amount );
      }
      else
      {
         auto& content_idx = d.get_index_type<content_index>().indices().get<graphene::db::by_id>();
         const auto& content_itr = content_idx.find( o.to );
         asset amount = o.amount;

         if( !content_itr->co_authors.empty() )
         {
            boost::multiprecision::int128_t amount_for_co_author;
            for( auto const &element : content_itr->co_authors )
            {
               amount_for_co_author = ( o.amount.amount.value * element.second ) / 10000ll ;
               d.adjust_balance( element.first, asset( static_cast<share_type>(amount_for_co_author), o.amount.asset_id) );
               amount.amount -= amount_for_co_author;
            }
         }

         to_acc = content_itr->author;
         suffix = " to content " + std::string(content_itr->id);

         if( amount.amount != 0 ) {
            FC_ASSERT( amount.amount > 0 );
            d.adjust_balance(to_acc, amount);
         }
      }

      d.create<transaction_detail_object>([&o, &d, &to_acc, &suffix](transaction_detail_object& obj)
                                             {
                                                obj.m_operation_type = (uint8_t)transaction_detail_object::transfer;

                                                obj.m_from_account = o.from;
                                                obj.m_to_account = to_acc;
                                                obj.m_transaction_amount = o.amount;
                                                obj.m_transaction_fee = o.fee;
                                                obj.m_transaction_encrypted_memo = o.memo;
                                                obj.m_str_description = "transfer" + suffix;
                                                obj.m_timestamp = d.head_block_time();
                                             });
      return void_result();
   } FC_CAPTURE_AND_RETHROW( (o) ) }

} } // graphene::chain

ext: cpp


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

/**
 * @file process_monitor.cpp
 * @brief Process monitor class
 */

#include <system_monitor/process_monitor/process_monitor.h>
#include <boost/format.hpp>
#include <boost/regex.hpp>
#include <string>
#include <vector>

ProcessMonitor::ProcessMonitor(const ros::NodeHandle & nh, const ros::NodeHandle & pnh)
: nh_(nh), pnh_(pnh)
{
  int index;

  gethostname(hostname_, sizeof(hostname_));

  pnh_.param<int>("num_of_procs", num_of_procs_, 5);

  updater_.setHardwareID(hostname_);
  updater_.add("Tasks Summary", this, &ProcessMonitor::monitorProcesses);

  for (index = 0; index < num_of_procs_; ++index) {
    auto task = std::make_shared<DiagTask>((boost::format("High-load Proc[%1%]") % index).str());
    load_tasks_.push_back(task);
    updater_.add(*task);
  }
  for (index = 0; index < num_of_procs_; ++index) {
    auto task = std::make_shared<DiagTask>((boost::format("High-mem Proc[%1%]") % index).str());
    memory_tasks_.push_back(task);
    updater_.add(*task);
  }
}

void ProcessMonitor::run(void)
{
  ros::Rate rate(1.0);

  while (ros::ok()) {
    ros::spinOnce();
    updater_.force_update();
    rate.sleep();
  }
}

void ProcessMonitor::monitorProcesses(diagnostic_updater::DiagnosticStatusWrapper & stat)
{
  bp::ipstream is_err;
  bp::ipstream is_out;
  std::ostringstream os;

  // Get processes
  bp::child c("top -bn1 -o %CPU -w 128", bp::std_out > is_out, bp::std_err > is_err);
  c.wait();
  if (c.exit_code() != 0) {
    is_err >> os.rdbuf();
    stat.summary(DiagStatus::ERROR, "top error");
    stat.add("top", os.str().c_str());
    setErrorContent(&load_tasks_, "top error", "top", os.str().c_str());
    setErrorContent(&memory_tasks_, "top error", "top", os.str().c_str());
    return;
  }

  is_out >> os.rdbuf();
  std::string str = os.str();

  // Get task summary
  getTasksSummary(stat, str);
  // Remove header
  removeHeader(stat, str);

  // Get high load processes
  getHighLoadProcesses(str);

  // Get high memory processes
  getHighMemoryProcesses(str);
}

void ProcessMonitor::getTasksSummary(
  diagnostic_updater::DiagnosticStatusWrapper & stat, const std::string & output)
{
  bp::pipe p;
  std::string line;

  // Echo output for grep
  {
    bp::ipstream is_out;
    bp::ipstream is_err;
    bp::child c((boost::format("echo %1%") % output).str(), bp::std_out > p, bp::std_err > is_err);
    c.wait();
    if (c.exit_code() != 0) {
      std::ostringstream os;
      is_err >> os.rdbuf();
      stat.summary(DiagStatus::ERROR, "echo error");
      stat.add("echo", os.str().c_str());
      return;
    }
  }
  // Find matching pattern of summary
  {
    bp::ipstream is_out;
    bp::child c("grep Tasks:", bp::std_out > is_out, bp::std_in < p);
    c.wait();
    // no matching line
    if (c.exit_code() != 0) {
      stat.summary(DiagStatus::ERROR, "matching pattern not found");
      stat.add("name", "Tasks:");
      return;
    }

    std::getline(is_out, line);
    boost::smatch match;
    boost::regex filter(
      "^Tasks: (\\d+) total,\\s+(\\d+) running,\\s+(\\d+) sleeping,\\s+(\\d+) stopped,\\s+(\\d+) "
      "zombie");

    if (boost::regex_match(line, match, filter)) {
      stat.add("total", match[1].str());
      stat.add("running", match[2].str());
      stat.add("sleeping", match[3].str());
      stat.add("stopped", match[4].str());
      stat.add("zombie", match[5].str());
      stat.summary(DiagStatus::OK, "OK");
    } else {
      stat.summary(DiagStatus::ERROR, "invalid format");
    }
  }
}

void ProcessMonitor::removeHeader(
  diagnostic_updater::DiagnosticStatusWrapper & stat, std::string & output)
{
  bp::pipe p1;
  bp::pipe p2;
  std::ostringstream os;

  // Echo output for sed
  {
    bp::ipstream is_err;
    bp::child c((boost::format("echo %1%") % output).str(), bp::std_out > p1, bp::std_err > is_err);
    c.wait();
    if (c.exit_code() != 0) {
      is_err >> os.rdbuf();
      stat.summary(DiagStatus::ERROR, "echo error");
      stat.add("echo", os.str().c_str());
      return;
    }
  }
  // Remove %Cpu section
  {
    bp::ipstream is_err;
    bp::child c("sed \"/^%Cpu/d\"", bp::std_out > p2, bp::std_err > is_err, bp::std_in < p1);
    c.wait();
    // no matching line
    if (c.exit_code() != 0) {
      stat.summary(DiagStatus::ERROR, "sed error");
      stat.add("sed", "Failed to remove header");
      return;
    }
  }
  // Remove header
  {
    bp::ipstream is_out;
    bp::ipstream is_err;
    bp::child c("sed \"1,6d\"", bp::std_out > is_out, bp::std_err > is_err, bp::std_in < p2);
    c.wait();
    // no matching line
    if (c.exit_code() != 0) {
      stat.summary(DiagStatus::ERROR, "sed error");
      stat.add("sed", "Failed to remove header");
      return;
    }
    // overwrite
    is_out >> os.rdbuf();
    output = os.str();
  }
}

void ProcessMonitor::getHighLoadProcesses(const std::string & output)
{
  bp::pipe p;
  std::ostringstream os;

  // Echo output for sed
  bp::ipstream is_out;
  bp::ipstream is_err;
  bp::child c((boost::format("echo %1%") % output).str(), bp::std_out > p, bp::std_err > is_err);
  c.wait();
  if (c.exit_code() != 0) {
    is_err >> os.rdbuf();
    setErrorContent(&load_tasks_, "echo error", "echo", os.str().c_str());
    return;
  }

  // Get top-rated
  getTopratedProcesses(&load_tasks_, &p);
}

void ProcessMonitor::getHighMemoryProcesses(const std::string & output)
{
  bp::pipe p1;
  bp::pipe p2;
  std::ostringstream os;

  // Echo output for sed
  {
    bp::ipstream is_out;
    bp::ipstream is_err;
    bp::child c((boost::format("echo %1%") % output).str(), bp::std_out > p1, bp::std_err > is_err);
    c.wait();
    if (c.exit_code() != 0) {
      is_err >> os.rdbuf();
      setErrorContent(&memory_tasks_, "echo error", "echo", os.str().c_str());
      return;
    }
  }
  // Sort by memory usage
  {
    bp::ipstream is_out;
    bp::ipstream is_err;
    bp::child c("sort -r -k 10", bp::std_out > p2, bp::std_err > is_err, bp::std_in < p1);
    c.wait();
    if (c.exit_code() != 0) {
      is_err >> os.rdbuf();
      setErrorContent(&memory_tasks_, "sort error", "sort", os.str().c_str());
      return;
    }
  }

  // Get top-rated
  getTopratedProcesses(&memory_tasks_, &p2);
}

void ProcessMonitor::getTopratedProcesses(
  std::vector<std::shared_ptr<DiagTask>> * tasks, bp::pipe * p)
{
  if (tasks == nullptr || p == nullptr) return;

  bp::ipstream is_out;
  bp::ipstream is_err;
  std::ostringstream os;

  bp::child c(
    (boost::format("sed -n \"1,%1% p\"") % num_of_procs_).str(), bp::std_out > is_out,
    bp::std_err > is_err, bp::std_in < *p);

  c.wait();
  // Failed to modify line
  if (c.exit_code() != 0) {
    is_err >> os.rdbuf();
    setErrorContent(tasks, "sed error", "sed", os.str().c_str());
    return;
  }

  std::vector<std::string> list;
  std::string line;
  int index = 0;

  while (std::getline(is_out, line) && !line.empty()) {
    boost::trim_left(line);
    boost::split(list, line, boost::is_space(), boost::token_compress_on);

    tasks->at(index)->setDiagnosticsStatus(DiagStatus::OK, "OK");
    tasks->at(index)->setProcessId(list[0]);
    tasks->at(index)->setUserName(list[1]);
    tasks->at(index)->setPriority(list[2]);
    tasks->at(index)->setNiceValue(list[3]);
    tasks->at(index)->setVirtualImage(list[4]);
    tasks->at(index)->setResidentSize(list[5]);
    tasks->at(index)->setSharedMemSize(list[6]);
    tasks->at(index)->setProcessStatus(list[7]);
    tasks->at(index)->setCPUUsage(list[8]);
    tasks->at(index)->setMemoryUsage(list[9]);
    tasks->at(index)->setCPUTime(list[10]);
    tasks->at(index)->setCommandName(list[11]);
    ++index;
  }
}

void ProcessMonitor::setErrorContent(
  std::vector<std::shared_ptr<DiagTask>> * tasks, const std::string & message,
  const std::string & error_command, const std::string & content)
{
  if (tasks == nullptr) return;

  for (auto itr = tasks->begin(); itr != tasks->end(); ++itr) {
    (*itr)->setDiagnosticsStatus(DiagStatus::ERROR, message);
    (*itr)->setErrorContent(error_command, content);
  }
}


text:
// Copyright (C) 2016-2018 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/yap/expression.hpp>

#include <boost/test/minimal.hpp>

template<typename T>
using term = boost::yap::terminal<boost::yap::expression, T>;

template<typename T>
using ref = boost::yap::expression_ref<boost::yap::expression, T>;

namespace yap = boost::yap;
namespace bh = boost::hana;

int test_main(int, char * [])
{
    {
        term<int> number = {{42}};

        auto fn = yap::make_expression_function(number);
        auto fn_copy = fn;

        BOOST_CHECK(fn() == 42);
        BOOST_CHECK(fn_copy() == 42);

        yap::value(number) = 21;

        BOOST_CHECK(fn() == 21);
        BOOST_CHECK(fn_copy() == 21);
    }

    {
        term<int> number = {{42}};

        auto fn = yap::make_expression_function(std::move(number));
        auto fn_copy = fn;

        BOOST_CHECK(fn() == 42);
        BOOST_CHECK(fn_copy() == 42);

        yap::value(number) = 21;

        BOOST_CHECK(fn() == 42);
        BOOST_CHECK(fn_copy() == 42);
    }

    {
        term<std::unique_ptr<int>> number = {
            {std::unique_ptr<int>(new int(42))}};

        auto fn = yap::make_expression_function(std::move(number));

        BOOST_CHECK(*fn() == 42);

        auto fn_2 = std::move(fn);
        BOOST_CHECK(*fn_2() == 42);

        yap::value(number) = std::unique_ptr<int>(new int(21));

        BOOST_CHECK(*fn_2() == 42);
    }

    return 0;
}


text:
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <boost/lexical_cast.hpp>
#include "yaml-cpp/yaml.h"
#include <jpeglib.h>
#include "utilities.h"

void yuv400ToCvmat(cv::Mat &dst, void *pYUV400, int nWidth, int nHeight, int bitDepth)
{
	IplImage *imgHeaderP;

	if (!pYUV400)
	{
		return;
	}

	if (bitDepth == 8)
	{
		imgHeaderP = cvCreateImageHeader(cvSize(nWidth, nHeight), IPL_DEPTH_8U, 1);
	}
	else
	{
		imgHeaderP = cvCreateImageHeader(cvSize(nWidth, nHeight), IPL_DEPTH_16U, 1);
	}

	cvSetData(imgHeaderP, (unsigned char *)pYUV400, nWidth);
	dst = cv::cvarrToMat(imgHeaderP);
	cvReleaseImageHeader(&imgHeaderP);
}

void yuvToRgb(const int &iY, const int &iU, const int &iV, int &iR, int &iG, int &iB)
{
	assert(&iR != NULL && &iG != NULL && &iB != NULL);

	iR = iY + 1.13983 * (iV - 128);
	iG = iY - 0.39465 * (iU - 128) - 0.58060 * (iV - 128);
	iB = iY + 2.03211 * (iU - 128);

	iR = iR > 255 ? 255 : iR;
	iR = iR < 0 ? 0 : iR;

	iG = iG > 255 ? 255 : iG;
	iG = iG < 0 ? 0 : iG;

	iB = iB > 255 ? 255 : iB;
	iB = iB < 0 ? 0 : iB;
}

void yuv422ToRgb24(unsigned char *uyvy422, unsigned char *rgb24, int width, int height)
{
	int iR, iG, iB;
	int iY0, iY1, iU, iV;
	int i = 0;
	int j = 0;
	for (i = 0; i < width * height * 2; i += 4)
	{
		iU = uyvy422[i + 0];
		iY0 = uyvy422[i + 1];
		iV = uyvy422[i + 2];
		iY1 = uyvy422[i + 3];

		yuvToRgb(iY0, iU, iV, iR, iG, iB);
		// rgb24[j++] = iR;
		// rgb24[j++] = iG;
		// rgb24[j++] = iB;
		rgb24[j++] = iB;
		rgb24[j++] = iG;
		rgb24[j++] = iR;
		yuvToRgb(iY1, iU, iV, iR, iG, iB);
		// rgb24[j++] = iR;
		// rgb24[j++] = iG;
		// rgb24[j++] = iB;
		rgb24[j++] = iB;
		rgb24[j++] = iG;
		rgb24[j++] = iR;
	}
}

void yuv422ToCvmat(cv::Mat &dst, void *pYUV422, int nWidth, int nHeight, int bitDepth)
{
	if (!pYUV422)
	{
		return;
	}
	unsigned char *rgb24_buffer = new unsigned char[nWidth * nHeight * 3];
	yuv422ToRgb24((unsigned char *)pYUV422, rgb24_buffer, nWidth, nHeight);
	dst = cv::Mat(nHeight, nWidth, CV_8UC3, rgb24_buffer).clone();
	delete[] rgb24_buffer;
}

bool loadCameraIntrinsics(const std::string &filename, std::vector<cv::Mat> &intrinsicKList, std::vector<cv::Mat> &intrinsicDList)
{
	if ((access(filename.c_str(), 0)) == -1)
	{
		printf("invalid intrinsicFile\n");
		return false;
	}
	YAML::Node yn = YAML::LoadFile(filename);
	std::string cameraId;
	for (int id = 0; id < 5; ++id)
	{
		// cameraId = std::to_string(i);
		cameraId = boost::lexical_cast<std::string>(id);
		cv::Mat intrinsicK, intrinsicD;

		if (yn[cameraId]["K"].IsDefined())
		{
			intrinsicK = cv::Mat::zeros(3, 3, CV_64FC1);
			for (int i = 0; i < yn[cameraId]["K"].size(); ++i)
			{
				intrinsicK.at<double>(i) = yn[cameraId]["K"][i].as<double>();
			}
			intrinsicKList.push_back(intrinsicK);
		}
		else
		{
			printf("invalid intrinsicFile content\n");
			return false;
		}
		if (yn[cameraId]["D"].IsDefined())
		{
			intrinsicD = cv::Mat::zeros(yn[cameraId]["D"].size(), 1, CV_64FC1);
			for (int i = 0; i < yn[cameraId]["D"].size(); ++i)
			{
				intrinsicD.at<double>(i) = yn[cameraId]["D"][i].as<double>();
			}
			intrinsicDList.push_back(intrinsicD);
		}
		else
		{
			printf("invalid intrinsicFile content\n");
			return false;
		}
	}
	return true;
}

void my_output_message (j_common_ptr ptr)
{
  return;
}

void print_mem(unsigned char* mem , unsigned int size)
{
	int i =0;
	for(i = 0 ; i < size ; i++)
	{
		printf("%02x " , mem[i]);
	}
	printf("\n");
}

int decompressJpeg(unsigned char *jpgBuffer, unsigned long jpgSize, unsigned char * &bmp, unsigned long& bmpSize)
{
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
  unsigned char *bmpBuffer;
  int rowStride, width, height, pixelSize;

  cinfo.err = jpeg_std_error(&jerr);
  cinfo.err->output_message = my_output_message;
	cinfo.err->error_exit = my_output_message;

  jpeg_create_decompress(&cinfo);
  jpeg_mem_src(&cinfo, jpgBuffer, jpgSize);

  int rc = jpeg_read_header(&cinfo, TRUE);
  if (rc != 1)
  {
    return -1;
  }

  jpeg_start_decompress(&cinfo);

  width = cinfo.output_width;
  height = cinfo.output_height;
  pixelSize = cinfo.output_components;
  bmpSize = width * height * pixelSize;
  bmpBuffer = (unsigned char *)malloc(bmpSize);
  rowStride = width * pixelSize;

  while (cinfo.output_scanline < cinfo.output_height)
  {
    unsigned char *buffer_array[1];
    buffer_array[0] = bmpBuffer +
                      (cinfo.output_scanline) * rowStride;

    jpeg_read_scanlines(&cinfo, buffer_array, 1);
  }
  bmp = bmpBuffer;
  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);
  return 0;
}

ext: cc


text:
//
// Created by taylor on 2020/8/24.
//

#include "backtrace.h"
#include <boost/filesystem.hpp>
#include <cstdlib>
#include <cstdio>
#include "Logger.h"
#include "Mutex.h"
#include <pthread.h>
#include <string>

namespace jupiter
{
    namespace {
        Mutex mutex_;
        std::string logger_name_;
        std::string dir_;
        std::string log_name_;

        pthread_once_t logger_is_initialized = PTHREAD_ONCE_INIT;
    }

    std::shared_ptr<spdlog::logger> logger;

    void logger_init_()
    {
        boost::filesystem::path cur_path = boost::filesystem::current_path();
        cur_path.append("/");
        cur_path.append(dir_);
        if (!boost::filesystem::exists(cur_path)) {
            if (!boost::filesystem::create_directory(cur_path)) {
                printf("create log dir failed: %s", cur_path.c_str());
                BACKTRACE();
                abort();
            }
        }
        spdlog::set_level(spdlog::level::trace);
        spdlog::set_async_mode(8192, spdlog::async_overflow_policy::block_retry, nullptr, std::chrono::milliseconds(1000));
        char buf[128] = {0};
        sprintf(buf, "%s/%s", cur_path.c_str(), log_name_.c_str());
        logger = spdlog::hourly_logger_mt(logger_name_, buf, 5 * 1024 * 1024);
        logger->set_pattern("[%Y-%m-%d %T.%e]: %v");
    }

    void logger_init(const char *logger_name, const char *dir, const char *log_name)
    {
        {
            MutexGuard guard(mutex_);
            if(logger_name_.empty() && dir_.empty() && log_name_.empty()) {
                logger_name_ = logger_name;
                dir_ = dir;
                log_name_ = log_name;
            }
        }
        pthread_once(&logger_is_initialized, &logger_init_);
    }

} // namespace jupiter

max_stars_repo_name: taylorgigi/libjupiter

max_issues_repo_name: taylorgigi/libjupiter

max_forks_repo_name: taylorgigi/libjupiter


text:
/*
 * Copyright (c) 2009, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "fps_view_controller.h"
#include <rviz/display_context.h>
#include <rviz/viewport_mouse_event.h>
#include <rviz/properties/enum_property.h>
#include <rviz/properties/float_property.h>
#include <rviz/properties/bool_property.h>
#include <rviz/properties/vector_property.h>

#include <OgreViewport.h>
#include <OgreCamera.h>
#include <OgreSceneNode.h>
#include <Eigen/Geometry>
#include <QSignalBlocker>

namespace rviz
{
const Ogre::Quaternion FPSViewController::ROBOT_TO_CAMERA_ROTATION =
    Ogre::Quaternion(Ogre::Radian(-Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_Y) *
    Ogre::Quaternion(Ogre::Radian(-Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_Z);

FPSViewController::FPSViewController()
{
  invert_z_->hide();

  yaw_property_ = new FloatProperty("Yaw", 0, "Rotation of the camera around the Z (up) axis.", this,
                                    SLOT(changedOrientation()), this);
  yaw_property_->setMax(Ogre::Math::PI);
  yaw_property_->setMin(-Ogre::Math::PI);

  pitch_property_ = new FloatProperty("Pitch", 0, "How much the camera is tipped downward.", this,
                                      SLOT(changedOrientation()), this);
  pitch_property_->setMax(Ogre::Math::PI);
  pitch_property_->setMin(-Ogre::Math::PI);

  roll_property_ = new FloatProperty("Roll", 0, "Rotation about the camera's view direction.", this,
                                     SLOT(changedOrientation()), this);
  roll_property_->setMax(Ogre::Math::PI);
  roll_property_->setMin(-Ogre::Math::PI);

  position_property_ = new VectorProperty("Position", Ogre::Vector3::ZERO, "Position of the camera.",
                                          this, SLOT(changedPosition()), this);
}

void FPSViewController::onInitialize()
{
  FramePositionTrackingViewController::onInitialize();
  camera_->setProjectionType(Ogre::PT_PERSPECTIVE);
  changedPosition();
}

void FPSViewController::reset()
{
  camera_->setPosition(Ogre::Vector3(5, 5, 10));
  camera_->lookAt(0, 0, 0);
  resetRoll();
  setPropertiesFromCamera();
  context_->queueRender();
}

void FPSViewController::mimic(ViewController* source_view)
{
  FramePositionTrackingViewController::mimic(source_view);
  auto source_camera = source_view->getCamera();
  camera_->setPosition(source_camera->getPosition());
  camera_->setOrientation(source_camera->getOrientation());
  setPropertiesFromCamera();
}

void FPSViewController::lookAt(const Ogre::Vector3& point)
{
  camera_->lookAt(target_scene_node_->convertWorldToLocalPosition(point));
  resetRoll();
  setPropertiesFromCamera();
}

void FPSViewController::handleMouseEvent(ViewportMouseEvent& event)
{
  if (event.shift())
    setStatus(
        "Left-Click: Rotate Roll.  Middle-Click: Move X/Y.  Right-Click:: Move Z.");
  else
    setStatus("Left-Click: Rotate Yaw/Pitch.  Shift Left-Click: Rotate Roll.  "
              "Middle-Click: Move X/Y.  Right-Click:: Move Z.");

  int32_t diff_x = 0;
  int32_t diff_y = 0;

  if (event.type == QEvent::MouseMove)
  {
    diff_x = event.x - event.last_x;
    diff_y = event.y - event.last_y;
  }

  if (event.left() && !event.shift())
  {
    setCursor(Rotate3D);
    rotate(-diff_x * 0.005, diff_y * 0.005, 0.0f);
  }
  else if (event.left() && event.shift())
  {
    setCursor(Rotate2D);
    int cx = event.viewport->getActualWidth() / 2;
    int cy = event.viewport->getActualHeight() / 2;

    float roll = atan2(event.last_y - cy, event.last_x - cx) - atan2(event.y - cy, event.x - cx);
    if (std::isfinite(roll))
      rotate(0.0f, 0.0f, roll);
  }
  else if (event.middle())
  {
    setCursor(MoveXY);
    move(diff_x * 0.01, -diff_y * 0.01, 0.0f);
  }
  else if (event.right())
  {
    setCursor(MoveZ);
    move(0.0f, 0.0f, diff_y * 0.1);
  }
  else
  {
    setCursor(event.shift() ? Rotate2D : Rotate3D);
  }

  if (event.wheel_delta != 0)
  {
    int diff = event.wheel_delta;
    move(0.0f, 0.0f, -diff * 0.01);
  }
}

Ogre::Quaternion FPSViewController::getOrientation(float yaw, float pitch, float roll)
{
  Eigen::Quaterniond q = Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ()) *
                         Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()) *
                         Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX());

  return Ogre::Quaternion(q.w(), q.x(), q.y(), q.z()) * ROBOT_TO_CAMERA_ROTATION;
}

void FPSViewController::setPropertiesFromCamera()
{
  Ogre::Quaternion q = camera_->getOrientation() * ROBOT_TO_CAMERA_ROTATION.Inverse();
  Eigen::Quaterniond quat(q.w, q.x, q.y, q.z);
  auto ypr = quat.toRotationMatrix().eulerAngles(2, 1, 0);

  QSignalBlocker blockY(yaw_property_);
  QSignalBlocker blockP(pitch_property_);
  QSignalBlocker blockR(roll_property_);
  QSignalBlocker block(position_property_);

  yaw_property_->setFloat(ypr[0]);
  pitch_property_->setFloat(ypr[1]);
  roll_property_->setFloat(ypr[2]);
  position_property_->setVector(camera_->getPosition());
}

void FPSViewController::resetRoll()
{
  Ogre::Quaternion q = camera_->getOrientation() * ROBOT_TO_CAMERA_ROTATION.Inverse();
  Eigen::Quaterniond quat(q.w, q.x, q.y, q.z);
  auto ypr = quat.toRotationMatrix().eulerAngles(2, 1, 0);
  camera_->setOrientation(getOrientation(ypr[0], ypr[1], Ogre::Math::PI));
}

void FPSViewController::onTargetFrameChanged(const Ogre::Vector3& old_reference_position,
                                             const Ogre::Quaternion& /*old_reference_orientation*/)
{
  position_property_->add(old_reference_position - reference_position_);
}

void FPSViewController::move(float x, float y, float z)
{
  Ogre::Vector3 translate(x, y, z);
  position_property_->add(camera_->getOrientation() * translate);
}

void FPSViewController::changedPosition()
{
  camera_->setPosition(position_property_->getVector());
  context_->queueRender();
}

inline void _rotate(FloatProperty* prop, float angle)
{
  if (angle == 0)
    return;

  QSignalBlocker block(prop);
  angle = fmod(prop->getFloat() + angle, Ogre::Math::TWO_PI);

  // map angle onto range -PI .. PI
  if (angle > Ogre::Math::PI)
    angle = -Ogre::Math::PI + fmod(angle, Ogre::Math::PI);
  if (angle < -Ogre::Math::PI)
    angle = Ogre::Math::PI + fmod(angle, Ogre::Math::PI);

  prop->setFloat(angle);
}

void FPSViewController::rotate(float yaw, float pitch, float roll)
{
  _rotate(yaw_property_, yaw);
  _rotate(pitch_property_, pitch);
  _rotate(roll_property_, roll);
  changedOrientation();
}

void FPSViewController::changedOrientation()
{
  camera_->setOrientation(getOrientation(yaw_property_->getFloat(), pitch_property_->getFloat(),
                                         roll_property_->getFloat()));
  context_->queueRender();
}

} // end namespace rviz

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(rviz::FPSViewController, rviz::ViewController)

max_stars_repo_name: fftn/rviz

max_issues_repo_name: fftn/rviz

max_forks_repo_name: fftn/rviz


text:
#pragma once
#include "lue/object/dataset.hpp"
#include <boost/filesystem.hpp>
#include <optional>

namespace lue {
namespace data_model {

// Try not to use this functionality!
// These are all implementation details. Never depend on the knowledge
// that is encoded in the implementation.

template<
    typename Property>
inline hdf5::Group property_set_group(
    Property& property)
{
    return property.parent().parent().parent();
}

template<
    typename Property>
inline hdf5::Group property_sets_group(
    Property& property)
{
    return property_set_group(property).parent();
}

template<
    typename Property>
inline hdf5::Group phenomena_group(
    Property& property)
{
    return property_sets_group(property).parent().parent();
}

template<
    typename Property>
inline hdf5::Group dataset_group(
    Property& property)
{
    return phenomena_group(property).parent();
}

template<
    typename Property>
inline PropertySet property_set(
    Property& property)
{
    return PropertySet{property_set_group(property)};
}

template<
    typename Property>
inline PropertySets property_sets(
    Property& property)
{
    return PropertySets{
        Collection<PropertySet>{property_sets_group(property)}};
}

template<
    typename Property>
inline Dataset dataset(
    Property& property)
{
    return Dataset{hdf5::File{dataset_group(property)}};
}

/*!
    @brief      Given a @a property, find another property pointed to
                by a @a path
*/
template<
    typename Property>
inline PropertyGroup property(
    Property& property,
    std::string const& pathname)
{
    // If path is absolute, it is relative to the dataset

    boost::filesystem::path path{pathname};

    assert(path.is_absolute());

    // Get the dataset
    auto dataset = data_model::dataset(property);
    assert(dataset.id().pathname() == "/");

    // Find the property
    std::optional<std::reference_wrapper<hdf5::Group>> parent;
    std::string property_name;

    auto it = path.begin();
    assert((*it).string() == "/");
    ++it;

    if(it != path.end()) {
        auto const phenomenon_name = (*it).string();

        if(dataset.phenomena().contains(phenomenon_name)) {
            auto& phenomenon = dataset.phenomena()[phenomenon_name];

            ++it;

            if(it != path.end()) {
                auto const property_set_name = (*it).string();

                std::optional<std::reference_wrapper<PropertySets>> property_sets;

                if(phenomenon.collection_property_sets().contains(property_set_name)) {
                    property_sets = phenomenon.collection_property_sets();
                }
                else if(phenomenon.property_sets().contains(property_set_name)) {
                    property_sets = phenomenon.property_sets();
                }

                if(property_sets) {
                    PropertySets& property_sets_ = *property_sets;
                    auto& property_set = property_sets_[property_set_name];

                    ++it;

                    if(it != path.end()) {
                        property_name = (*it).string();

                        if(property_set.properties().contains(property_name)) {

                            assert(++it == path.end());

                            parent =
                                property_set.properties().collection_group(
                                    property_name);
                        }
                    }
                }
            }
        }
    }

    if(!parent) {
        throw std::runtime_error("Property cannot be found");
    }

    return PropertyGroup{*parent, property_name};
}

}  // namespace data_model
}  // namespace lue

max_stars_repo_name: OliverSchmitz/lue

max_issues_repo_name: OliverSchmitz/lue

max_forks_repo_name: OliverSchmitz/lue


text:
#include <iostream>
#include <memory>
#include <boost/program_options.hpp>
#include <boost/program_options/options_description.hpp>
#include "settings.h"
#include "system_status.h"
#include "airdata.h"
#include "display.h"
#include "image_screen.h"
#include "log_reader_telemetry_client.h"
#include "units.h"

constexpr static const char* kOptionHelp =
    "help";
constexpr static const char* kOptionSettingsFilename =
    "settings_filename";
constexpr static const char* kOptionTelemetryLogFilename =
    "telemetry_log_filename";
constexpr static const char* kOptionOutputBase =
    "output_base";

constexpr uint kImageNameBufSize = 2048;

constexpr uint kScreenWidth = 480;
constexpr uint kScreenHeight = 272;

constexpr uint kSamplesPerSecond = 20;
constexpr uint kFramesPerSecond = 25;

constexpr static std::chrono::duration<unsigned int, std::milli>
    kFrameInterval(1000 / kFramesPerSecond);

namespace po = boost::program_options;

static po::options_description add_options() {
  po::options_description desc("Airball replay command line options");
  desc.add_options()
      (
          kOptionHelp,
          "produce help message"
      )
      (
          kOptionSettingsFilename,
          po::value<std::string>(),
          "path to settings JSON file"
      )
      (
          kOptionTelemetryLogFilename,
          po::value<std::string>(),
          "path to telemetry log"
      )
      (
          kOptionOutputBase,
          po::value<std::string>(),
          "base name of output image files"
      );
  return desc;
}

int main(int argc, char **argv) {
  po::options_description options = add_options();
  po::variables_map vm;
  po::store(po::parse_command_line(argc, argv, options), vm);
  po::notify(vm);

  if (vm.count(kOptionHelp)) {
    std::cout << options << std::endl;
    return 1;
  }

  airball::Settings settings(
      vm[kOptionSettingsFilename].as<std::string>());
  airball::SystemStatus status;
  airball::Airdata airdata;
  auto screen = std::unique_ptr<airball::ImageScreen>(
      new airball::ImageScreen(kScreenWidth, kScreenHeight));
  auto telemetry = std::unique_ptr<airball::TelemetryClient>(
      new airball::LogReaderTelemetryClient(
          vm[kOptionTelemetryLogFilename].as<std::string>(),
          kSamplesPerSecond,
          0,
          false));
  airball::Display display(screen.get(), &airdata, &settings, &status);

  uint64_t img_index = 0;
  char img_name_buf[kImageNameBufSize];

  auto update = [&](const airdata_sample* s) {
    airdata.update(s,
                   kPascalsPerInHg * settings.baro_setting(),
                     settings.ball_smoothing_factor(),
                     settings.vsi_smoothing_factor());
    status.update(static_cast<const class sample*>(s));
  };

  auto paint = [&]() {
    display.paint();
    sprintf(
        img_name_buf,
        "./%s_%09lu.png",
        vm[kOptionOutputBase].as<std::string>().c_str(),
        img_index++);
    screen->write_to_png(img_name_buf);
  };

  bool time_initialized(false);
  std::chrono::system_clock::time_point next_frame_time;

  while (true) {
    auto sample = telemetry->get();
    if (sample == nullptr) { break; }

    auto ad_sample = dynamic_cast<const airdata_sample*>(sample.get());
    if (ad_sample == nullptr) { continue; }

    if (!time_initialized) {
      next_frame_time = ad_sample->get_time();
      time_initialized = true;
    }

    while (next_frame_time < ad_sample->get_time()) {
      paint();
      next_frame_time += kFrameInterval;
    }

    update(ad_sample);
  }
}

max_stars_repo_name: dinglewanker/airball-embedded

max_issues_repo_name: dinglewanker/airball-embedded

max_forks_repo_name: dinglewanker/airball-embedded