<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: unoautopilot.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 19:33:22 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _EXTENSIONS_DBP_UNOAUTOPILOT_HXX_
#define _EXTENSIONS_DBP_UNOAUTOPILOT_HXX_

#ifndef _SVT_GENERICUNODIALOG_HXX_
#include <svtools/genericunodialog.hxx>
#endif
#ifndef _COMPHELPER_PROPERTY_ARRAY_HELPER_HXX_
#include <comphelper/proparrhlp.hxx>
#endif
#ifndef _EXTENSIONS_COMPONENT_MODULE_HXX_
#include "componentmodule.hxx"
#endif
#ifndef _CPPUHELPER_TYPEPROVIDER_HXX_
#include <cppuhelper/typeprovider.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

//.........................................................................
namespace dbp
{
//.........................................................................

    //=====================================================================
    //= IServiceInfo
    //=====================================================================
    /** interface for the SERVICEINFO template parameter of the OUnoAutoPilot class
    */
    struct IServiceInfo
    {
    public:
        ::rtl::OUString     getImplementationName() const;
        ::com::sun::star::uno::Sequence< ::rtl::OUString >
                            getServiceNames() const;
    };

    //=====================================================================
    //= OUnoAutoPilot
    //=====================================================================
    typedef ::svt::OGenericUnoDialog    OUnoAutoPilot_Base;
    template <class TYPE, class SERVICEINFO>
    class OUnoAutoPilot
            :public OUnoAutoPilot_Base
            ,public ::comphelper::OPropertyArrayUsageHelper< OUnoAutoPilot< TYPE, SERVICEINFO > >
            ,public OModuleResourceClient
    {
        OUnoAutoPilot(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB);

    protected:
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    m_xObjectModel;

    public:
        // XTypeProvider
        virtual ::com::sun::star::uno::Sequence<sal_Int8> SAL_CALL getImplementationId(  ) throw(::com::sun::star::uno::RuntimeException);

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName() throw(::com::sun::star::uno::RuntimeException);
        virtual ::comphelper::StringSequence SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);

        // XServiceInfo - static methods
        static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static(void) throw( ::com::sun::star::uno::RuntimeException );
        static ::rtl::OUString getImplementationName_Static(void) throw( ::com::sun::star::uno::RuntimeException );
        static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
                SAL_CALL Create(const ::com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >&);

        // XPropertySet
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo>  SAL_CALL getPropertySetInfo() throw(::com::sun::star::uno::RuntimeException);
        virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();

        // OPropertyArrayUsageHelper
        virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;

    protected:
    // OGenericUnoDialog overridables
        virtual Dialog* createDialog(Window* _pParent);
        virtual void implInitialize(const com::sun::star::uno::Any& _rValue);
    };

#include "unoautopilot.inl"

//.........................................................................
}   // namespace dbp
//.........................................................................

#endif // _EXTENSIONS_DBP_UNOAUTOPILOT_HXX_

<commit_msg>INTEGRATION: CWS changefileheader (1.3.472); FILE MERGED 2008/04/01 15:15:06 thb 1.3.472.3: #i85898# Stripping all external header guards 2008/04/01 12:29:44 thb 1.3.472.2: #i85898# Stripping all external header guards 2008/03/31 12:31:28 rt 1.3.472.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: unoautopilot.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _EXTENSIONS_DBP_UNOAUTOPILOT_HXX_
#define _EXTENSIONS_DBP_UNOAUTOPILOT_HXX_

#include <svtools/genericunodialog.hxx>
#include <comphelper/proparrhlp.hxx>
#include "componentmodule.hxx"
#include <cppuhelper/typeprovider.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>

//.........................................................................
namespace dbp
{
//.........................................................................

    //=====================================================================
    //= IServiceInfo
    //=====================================================================
    /** interface for the SERVICEINFO template parameter of the OUnoAutoPilot class
    */
    struct IServiceInfo
    {
    public:
        ::rtl::OUString     getImplementationName() const;
        ::com::sun::star::uno::Sequence< ::rtl::OUString >
                            getServiceNames() const;
    };

    //=====================================================================
    //= OUnoAutoPilot
    //=====================================================================
    typedef ::svt::OGenericUnoDialog    OUnoAutoPilot_Base;
    template <class TYPE, class SERVICEINFO>
    class OUnoAutoPilot
            :public OUnoAutoPilot_Base
            ,public ::comphelper::OPropertyArrayUsageHelper< OUnoAutoPilot< TYPE, SERVICEINFO > >
            ,public OModuleResourceClient
    {
        OUnoAutoPilot(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB);

    protected:
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    m_xObjectModel;

    public:
        // XTypeProvider
        virtual ::com::sun::star::uno::Sequence<sal_Int8> SAL_CALL getImplementationId(  ) throw(::com::sun::star::uno::RuntimeException);

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName() throw(::com::sun::star::uno::RuntimeException);
        virtual ::comphelper::StringSequence SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);

        // XServiceInfo - static methods
        static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static(void) throw( ::com::sun::star::uno::RuntimeException );
        static ::rtl::OUString getImplementationName_Static(void) throw( ::com::sun::star::uno::RuntimeException );
        static ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
                SAL_CALL Create(const ::com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >&);

        // XPropertySet
        virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo>  SAL_CALL getPropertySetInfo() throw(::com::sun::star::uno::RuntimeException);
        virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();

        // OPropertyArrayUsageHelper
        virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;

    protected:
    // OGenericUnoDialog overridables
        virtual Dialog* createDialog(Window* _pParent);
        virtual void implInitialize(const com::sun::star::uno::Any& _rValue);
    };

#include "unoautopilot.inl"

//.........................................................................
}   // namespace dbp
//.........................................................................

#endif // _EXTENSIONS_DBP_UNOAUTOPILOT_HXX_

<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  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 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.
 *
 * $Id$
 *
 */

#ifndef PCL_FEATURES_IMPL_FPFH_H_
#define PCL_FEATURES_IMPL_FPFH_H_

#include "pcl/features/fpfh.h"

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> bool
pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::computePairFeatures (
      const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,
      int p_idx, int q_idx, float &f1, float &f2, float &f3, float &f4)
{
  // Compute the Cartesian difference between the two points
  Eigen::Vector4f delta = cloud.points[q_idx].getVector4fMap () - cloud.points[p_idx].getVector4fMap ();
  delta[3] = 0;

  // Compute the Euclidean norm = || p_idx - q_idx ||
  float distance_sqr = delta.squaredNorm ();

  if (distance_sqr == 0)
  {
    PCL_DEBUG ("Euclidean distance between points %d and %d is 0!\n", p_idx, q_idx);
    f1 = f2 = f3 = f4 = 0;
    return (false);
  }

  // Estimate f4 = || delta ||
  f4 = sqrt (distance_sqr);

  // Create a Darboux frame coordinate system u-v-w
  // u = n1; v = (p_idx - q_idx) x u / || (p_idx - q_idx) x u ||; w = u x v
  pcl::Vector4fMapConst u = normals.points[p_idx].getNormalVector4fMap ();

  // Estimate f3 = u * delta / || delta ||
  // delta[3] = 0 (line 59)
  f3 = u.dot (delta) / f4;

  // v = delta * u
  Eigen::Vector4f v = Eigen::Vector4f::Zero ();
  v = delta.cross3 (u);

  distance_sqr = v.squaredNorm ();
  if (distance_sqr == 0)
  {
    PCL_DEBUG ("Norm of Delta x U is 0 for point %d and %d!\n", p_idx, q_idx);
    f1 = f2 = f3 = f4 = 0;
    return (false);
  }

  // Copy the q_idx normal
  Eigen::Vector4f nq (normals.points[q_idx].normal_x,
                      normals.points[q_idx].normal_y,
                      normals.points[q_idx].normal_z,
                      0);

  // Normalize the vector
  v /= sqrt (distance_sqr);

  // Compute delta (w) = u x v
  delta = u.cross3 (v);

  // Compute f2 = v * n2;
  // v[3] = 0 (line 82)
  f2 = v.dot (nq);

  // Compute f1 = arctan (w * n2, u * n2) i.e. angle of n2 in the x=u, y=w coordinate system
  // delta[3] = 0 (line 59), nq[3] = 0 (line 97)
  f1 = atan2f (delta.dot (nq), u.dot (nq));       // @todo: optimize this

  return (true);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
void pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::
computePointSPFHSignature (const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,
                           int p_idx, const std::vector<int> &indices,
                           Eigen::MatrixXf &hist_f1, Eigen::MatrixXf &hist_f2, Eigen::MatrixXf &hist_f3)
{
  Eigen::Vector4f pfh_tuple;
  // Get the number of bins from the histograms size
  int nr_bins_f1 = hist_f1.cols ();
  int nr_bins_f2 = hist_f2.cols ();
  int nr_bins_f3 = hist_f3.cols ();

  // Factorization constant
  float hist_incr = 100.0 / (float)(indices.size () - 1);

  // Iterate over all the points in the neighborhood
  for (size_t idx = 0; idx < indices.size (); ++idx)
  {
    // Avoid unnecessary returns
    if (p_idx == indices[idx])
      continue;

    // Compute the pair P to NNi
    if (!computePairFeatures (cloud, normals, p_idx, indices[idx], pfh_tuple[0], pfh_tuple[1], pfh_tuple[2], pfh_tuple[3]))
      continue;

    // Normalize the f1, f2, f3 features and push them in the histogram
    int h_index = floor (nr_bins_f1 * ((pfh_tuple[0] + M_PI) * d_pi_));
    if (h_index < 0)           h_index = 0;
    if (h_index >= nr_bins_f1) h_index = nr_bins_f1 - 1;
    hist_f1 (p_idx, h_index) += hist_incr;

    h_index = floor (nr_bins_f2 * ((pfh_tuple[1] + 1.0) * 0.5));
    if (h_index < 0)           h_index = 0;
    if (h_index >= nr_bins_f2) h_index = nr_bins_f2 - 1;
    hist_f2 (p_idx, h_index) += hist_incr;

    h_index = floor (nr_bins_f3 * ((pfh_tuple[2] + 1.0) * 0.5));
    if (h_index < 0)           h_index = 0;
    if (h_index >= nr_bins_f3) h_index = nr_bins_f3 - 1;
    hist_f3 (p_idx, h_index) += hist_incr;
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::weightPointSPFHSignature (
      const Eigen::MatrixXf &hist_f1, const Eigen::MatrixXf &hist_f2, const Eigen::MatrixXf &hist_f3,
      const std::vector<int> &indices, const std::vector<float> &dists, Eigen::VectorXf &fpfh_histogram)
{
  assert (indices.size () == dists.size ());
  double sum_f1 = 0.0, sum_f2 = 0.0, sum_f3 = 0.0;
  float weight = 0.0, val_f1, val_f2, val_f3;

  // Get the number of bins from the histograms size
  int nr_bins_f1 = hist_f1.cols ();
  int nr_bins_f2 = hist_f2.cols ();
  int nr_bins_f3 = hist_f3.cols ();
  int nr_bins_f12 = nr_bins_f1 + nr_bins_f2;

  // Use the entire patch
  for (size_t idx = 0, data_size = indices.size (); idx < data_size; ++idx)
  {
    // Minus the query point itself
    if (dists[idx] == 0)
      continue;

    // Standard weighting function used
    weight = 1.0 / dists[idx];

    // Weight the SPFH of the query point with the SPFH of its neighbors
    for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i)
    {
      val_f1 = hist_f1 (indices[idx], f1_i) * weight;
      sum_f1 += val_f1;
      fpfh_histogram[f1_i] += val_f1;
    }

    for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i)
    {
      val_f2 = hist_f2 (indices[idx], f2_i) * weight;
      sum_f2 += val_f2;
      fpfh_histogram[f2_i + nr_bins_f1] += val_f2;
    }

    for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i)
    {
      val_f3 = hist_f3 (indices[idx], f3_i) * weight;
      sum_f3 += val_f3;
      fpfh_histogram[f3_i + nr_bins_f12] += val_f3;
    }
  }

  if (sum_f1 != 0)
    sum_f1 = 100.0 / sum_f1;           // histogram values sum up to 100
  if (sum_f2 != 0)
    sum_f2 = 100.0 / sum_f2;           // histogram values sum up to 100
  if (sum_f3 != 0)
    sum_f3 = 100.0 / sum_f3;           // histogram values sum up to 100

  // Adjust final FPFH values
  for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i)
    fpfh_histogram[f1_i] *= sum_f1;
  for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i)
    fpfh_histogram[f2_i + nr_bins_f1] *= sum_f2;
  for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i)
    fpfh_histogram[f3_i + nr_bins_f12] *= sum_f3;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  // Allocate enough space to hold the NN search results
  // \note This resize is irrelevant for a radiusSearch ().
  std::vector<int> nn_indices (k_);
  std::vector<float> nn_dists (k_);

  std::set<int> spfh_indices;
  std::vector<int> spfh_hist_lookup (surface_->points.size ());

  // Build a list of (unique) indices for which we will need to compute SPFH signatures
  // (We need an SPFH signature for every point that is a neighbor of any point in input_[indices_])
  if (surface_ != input_ ||
      indices_->size () != surface_->points.size ())
  {
    for (size_t idx = 0; idx < indices_->size (); ++idx)
    {
      int p_idx = (*indices_)[idx];
      this->searchForNeighbors (p_idx, search_parameter_, nn_indices, nn_dists);

      spfh_indices.insert (nn_indices.begin (), nn_indices.end ());
    }
  }
  else
  {
    // Special case: When a feature must be computed at every point, there is no need for a neighborhood search
    for (size_t idx = 0; idx < indices_->size (); ++idx)
      spfh_indices.insert (idx);
  }

  // Initialize the arrays that will store the SPFH signatures
  size_t data_size = spfh_indices.size ();
  hist_f1_.setZero (data_size, nr_bins_f1_);
  hist_f2_.setZero (data_size, nr_bins_f2_);
  hist_f3_.setZero (data_size, nr_bins_f3_);

  // Compute SPFH signatures for every point that needs them
  std::set<int>::iterator spfh_indices_itr = spfh_indices.begin ();
  for (size_t i = 0; i < spfh_indices.size (); ++i)
  {
    // Get the next point index
    int p_idx = *spfh_indices_itr;
    ++spfh_indices_itr;

    // Find the neighborhood around p_idx
    this->searchForNeighbors (p_idx, search_parameter_, nn_indices, nn_dists);

    // Estimate the SPFH signature around p_idx
    computePointSPFHSignature (*surface_, *normals_, i, nn_indices, hist_f1_, hist_f2_, hist_f3_);

    // Populate a lookup table for converting a point index to its corresponding row in the spfh_hist_* matrices
    spfh_hist_lookup[p_idx] = i;
  }

  // Intialize the array that will store the FPFH signature
  int nr_bins = nr_bins_f1_ + nr_bins_f2_ + nr_bins_f3_;
  fpfh_histogram_.setZero (nr_bins);

  // Iterate over the entire index vector
  for (size_t idx = 0; idx < indices_->size (); ++idx)
  {
    // Find the indices of point idx's neighbors...
    this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists);

    // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices
    // instead of indices into surface_->points
    for (size_t i = 0; i < nn_indices.size (); ++i)
      nn_indices[i] = spfh_hist_lookup[nn_indices[i]];

    // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ...
    weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_);

    // ...and copy it into the output cloud
    for (int d = 0; d < fpfh_histogram_.size (); ++d)
      output.points[idx].histogram[d] = fpfh_histogram_[d];

    fpfh_histogram_.setZero ();
  }

}

#define PCL_INSTANTIATE_FPFHEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::FPFHEstimation<T,NT,OutT>;

#endif    // PCL_FEATURES_IMPL_FPFH_H_

<commit_msg>FPFHEstimation now uses the pcl::computePairFeatures () method instead of its own private copy of it<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  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 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.
 *
 * $Id$
 *
 */

#ifndef PCL_FEATURES_IMPL_FPFH_H_
#define PCL_FEATURES_IMPL_FPFH_H_

#include "pcl/features/fpfh.h"
#include <pcl/features/pfh.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> bool
pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::computePairFeatures (
      const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,
      int p_idx, int q_idx, float &f1, float &f2, float &f3, float &f4)
{
  pcl::computePairFeatures (cloud.points[p_idx].getVector4fMap (), normals.points[p_idx].getNormalVector4fMap (),
                             cloud.points[q_idx].getVector4fMap (), normals.points[q_idx].getNormalVector4fMap (),
                             f1, f2, f3, f4);
  return (true);
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
void pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::
computePointSPFHSignature (const pcl::PointCloud<PointInT> &cloud, const pcl::PointCloud<PointNT> &normals,
                           int p_idx, const std::vector<int> &indices,
                           Eigen::MatrixXf &hist_f1, Eigen::MatrixXf &hist_f2, Eigen::MatrixXf &hist_f3)
{
  Eigen::Vector4f pfh_tuple;
  // Get the number of bins from the histograms size
  int nr_bins_f1 = hist_f1.cols ();
  int nr_bins_f2 = hist_f2.cols ();
  int nr_bins_f3 = hist_f3.cols ();

  // Factorization constant
  float hist_incr = 100.0 / (float)(indices.size () - 1);

  // Iterate over all the points in the neighborhood
  for (size_t idx = 0; idx < indices.size (); ++idx)
  {
    // Avoid unnecessary returns
    if (p_idx == indices[idx])
      continue;

    // Compute the pair P to NNi
    if (!computePairFeatures (cloud, normals, p_idx, indices[idx], pfh_tuple[0], pfh_tuple[1], pfh_tuple[2], pfh_tuple[3]))
      continue;

    // Normalize the f1, f2, f3 features and push them in the histogram
    int h_index = floor (nr_bins_f1 * ((pfh_tuple[0] + M_PI) * d_pi_));
    if (h_index < 0)           h_index = 0;
    if (h_index >= nr_bins_f1) h_index = nr_bins_f1 - 1;
    hist_f1 (p_idx, h_index) += hist_incr;

    h_index = floor (nr_bins_f2 * ((pfh_tuple[1] + 1.0) * 0.5));
    if (h_index < 0)           h_index = 0;
    if (h_index >= nr_bins_f2) h_index = nr_bins_f2 - 1;
    hist_f2 (p_idx, h_index) += hist_incr;

    h_index = floor (nr_bins_f3 * ((pfh_tuple[2] + 1.0) * 0.5));
    if (h_index < 0)           h_index = 0;
    if (h_index >= nr_bins_f3) h_index = nr_bins_f3 - 1;
    hist_f3 (p_idx, h_index) += hist_incr;
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::weightPointSPFHSignature (
      const Eigen::MatrixXf &hist_f1, const Eigen::MatrixXf &hist_f2, const Eigen::MatrixXf &hist_f3,
      const std::vector<int> &indices, const std::vector<float> &dists, Eigen::VectorXf &fpfh_histogram)
{
  assert (indices.size () == dists.size ());
  double sum_f1 = 0.0, sum_f2 = 0.0, sum_f3 = 0.0;
  float weight = 0.0, val_f1, val_f2, val_f3;

  // Get the number of bins from the histograms size
  int nr_bins_f1 = hist_f1.cols ();
  int nr_bins_f2 = hist_f2.cols ();
  int nr_bins_f3 = hist_f3.cols ();
  int nr_bins_f12 = nr_bins_f1 + nr_bins_f2;

  // Use the entire patch
  for (size_t idx = 0, data_size = indices.size (); idx < data_size; ++idx)
  {
    // Minus the query point itself
    if (dists[idx] == 0)
      continue;

    // Standard weighting function used
    weight = 1.0 / dists[idx];

    // Weight the SPFH of the query point with the SPFH of its neighbors
    for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i)
    {
      val_f1 = hist_f1 (indices[idx], f1_i) * weight;
      sum_f1 += val_f1;
      fpfh_histogram[f1_i] += val_f1;
    }

    for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i)
    {
      val_f2 = hist_f2 (indices[idx], f2_i) * weight;
      sum_f2 += val_f2;
      fpfh_histogram[f2_i + nr_bins_f1] += val_f2;
    }

    for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i)
    {
      val_f3 = hist_f3 (indices[idx], f3_i) * weight;
      sum_f3 += val_f3;
      fpfh_histogram[f3_i + nr_bins_f12] += val_f3;
    }
  }

  if (sum_f1 != 0)
    sum_f1 = 100.0 / sum_f1;           // histogram values sum up to 100
  if (sum_f2 != 0)
    sum_f2 = 100.0 / sum_f2;           // histogram values sum up to 100
  if (sum_f3 != 0)
    sum_f3 = 100.0 / sum_f3;           // histogram values sum up to 100

  // Adjust final FPFH values
  for (int f1_i = 0; f1_i < nr_bins_f1; ++f1_i)
    fpfh_histogram[f1_i] *= sum_f1;
  for (int f2_i = 0; f2_i < nr_bins_f2; ++f2_i)
    fpfh_histogram[f2_i + nr_bins_f1] *= sum_f2;
  for (int f3_i = 0; f3_i < nr_bins_f3; ++f3_i)
    fpfh_histogram[f3_i + nr_bins_f12] *= sum_f3;
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::FPFHEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  // Allocate enough space to hold the NN search results
  // \note This resize is irrelevant for a radiusSearch ().
  std::vector<int> nn_indices (k_);
  std::vector<float> nn_dists (k_);

  std::set<int> spfh_indices;
  std::vector<int> spfh_hist_lookup (surface_->points.size ());

  // Build a list of (unique) indices for which we will need to compute SPFH signatures
  // (We need an SPFH signature for every point that is a neighbor of any point in input_[indices_])
  if (surface_ != input_ ||
      indices_->size () != surface_->points.size ())
  {
    for (size_t idx = 0; idx < indices_->size (); ++idx)
    {
      int p_idx = (*indices_)[idx];
      this->searchForNeighbors (p_idx, search_parameter_, nn_indices, nn_dists);

      spfh_indices.insert (nn_indices.begin (), nn_indices.end ());
    }
  }
  else
  {
    // Special case: When a feature must be computed at every point, there is no need for a neighborhood search
    for (size_t idx = 0; idx < indices_->size (); ++idx)
      spfh_indices.insert (idx);
  }

  // Initialize the arrays that will store the SPFH signatures
  size_t data_size = spfh_indices.size ();
  hist_f1_.setZero (data_size, nr_bins_f1_);
  hist_f2_.setZero (data_size, nr_bins_f2_);
  hist_f3_.setZero (data_size, nr_bins_f3_);

  // Compute SPFH signatures for every point that needs them
  std::set<int>::iterator spfh_indices_itr = spfh_indices.begin ();
  for (size_t i = 0; i < spfh_indices.size (); ++i)
  {
    // Get the next point index
    int p_idx = *spfh_indices_itr;
    ++spfh_indices_itr;

    // Find the neighborhood around p_idx
    this->searchForNeighbors (p_idx, search_parameter_, nn_indices, nn_dists);

    // Estimate the SPFH signature around p_idx
    computePointSPFHSignature (*surface_, *normals_, i, nn_indices, hist_f1_, hist_f2_, hist_f3_);

    // Populate a lookup table for converting a point index to its corresponding row in the spfh_hist_* matrices
    spfh_hist_lookup[p_idx] = i;
  }

  // Intialize the array that will store the FPFH signature
  int nr_bins = nr_bins_f1_ + nr_bins_f2_ + nr_bins_f3_;
  fpfh_histogram_.setZero (nr_bins);

  // Iterate over the entire index vector
  for (size_t idx = 0; idx < indices_->size (); ++idx)
  {
    // Find the indices of point idx's neighbors...
    this->searchForNeighbors ((*indices_)[idx], search_parameter_, nn_indices, nn_dists);

    // ... and remap the nn_indices values so that they represent row indices in the spfh_hist_* matrices
    // instead of indices into surface_->points
    for (size_t i = 0; i < nn_indices.size (); ++i)
      nn_indices[i] = spfh_hist_lookup[nn_indices[i]];

    // Compute the FPFH signature (i.e. compute a weighted combination of local SPFH signatures) ...
    weightPointSPFHSignature (hist_f1_, hist_f2_, hist_f3_, nn_indices, nn_dists, fpfh_histogram_);

    // ...and copy it into the output cloud
    for (int d = 0; d < fpfh_histogram_.size (); ++d)
      output.points[idx].histogram[d] = fpfh_histogram_[d];

    fpfh_histogram_.setZero ();
  }

}

#define PCL_INSTANTIATE_FPFHEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::FPFHEstimation<T,NT,OutT>;

#endif    // PCL_FEATURES_IMPL_FPFH_H_

<|endoftext|>


<commit_before>#include <CQHistoryLineEdit.h>
#include <CHistory.h>
#include <QKeyEvent>

CQHistoryLineEdit::
CQHistoryLineEdit(QWidget *parent) :
 QLineEdit(parent)
{
  history_ = std::make_unique<CHistory>();

  connect(this, SIGNAL(returnPressed()), this, SLOT(execSlot()));
}

CQHistoryLineEdit::
~CQHistoryLineEdit()
{
}

void
CQHistoryLineEdit::
execSlot()
{
  QString str = text();

  emit exec(str);

  QString str1 = str.simplified();

  if (str1.length())
    history_->addCommand(str1.toStdString());

  setText("");
}

void
CQHistoryLineEdit::
keyPressEvent(QKeyEvent *event)
{
  int key = event->key();

  switch (key) {
    case Qt::Key_Up: {
      std::string cmd;

      if (history_->getPrevCommand(cmd))
        setText(cmd.c_str());

      break;
    }
    case Qt::Key_Down: {
      std::string cmd;

      if (history_->getNextCommand(cmd))
        setText(cmd.c_str());

      break;
    }
    default:
      QLineEdit::keyPressEvent(event);

      break;
  }
}
<commit_msg>new files<commit_after>#include <CQHistoryLineEdit.h>
#include <CHistory.h>
#include <QKeyEvent>

CQHistoryLineEdit::
CQHistoryLineEdit(QWidget *parent) :
 QLineEdit(parent)
{
  history_ = std::make_unique<CHistory>();

  connect(this, SIGNAL(returnPressed()), this, SLOT(execSlot()));
}

CQHistoryLineEdit::
~CQHistoryLineEdit()
{
}

void
CQHistoryLineEdit::
execSlot()
{
  QString str = text();

  emit exec(str);

  QString str1 = str.trimmed();

  if (str1.length())
    history_->addCommand(str1.toStdString());

  setText("");
}

void
CQHistoryLineEdit::
keyPressEvent(QKeyEvent *event)
{
  int key = event->key();

  switch (key) {
    case Qt::Key_Up: {
      std::string cmd;

      if (history_->getPrevCommand(cmd))
        setText(cmd.c_str());

      break;
    }
    case Qt::Key_Down: {
      std::string cmd;

      if (history_->getNextCommand(cmd))
        setText(cmd.c_str());

      break;
    }
    default:
      QLineEdit::keyPressEvent(event);

      break;
  }
}
<|endoftext|>


<commit_before>/// Copyright 2016 Pinterest Inc.
///
/// 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.

//
// @author bol (bol@pinterest.com)
//

#include "common/file_watcher.h"

#include <folly/FileUtil.h>
#include <folly/SpookyHashV2.h>
#include <folly/ThreadName.h>
#include <sys/inotify.h>

#include <string>

#include "gflags/gflags.h"

/*
 * TODO(shu): Commented temporarily.
 * Reason: In Pinability scorer shared object
 * we want to use file watcher to watch model files. The flag will
 * be defined twice since we both static and dynamic link file watcher.
 * Since this flag is not being set actively, making it a
 * hard coded number for now.
 */
// DEFINE_int32(recheck_removed_file_interval_ms, 2 * 1000,
//              "The interval for checking removed files");
const int kRecheckRemovedFileIntervalMs = 2000;

namespace common {
FileWatcher* FileWatcher::Instance() {
  static FileWatcher instance;
  return &instance;
}

FileWatcher::FileWatcher()
    : evb_()
    , fd_(::inotify_init())
    , handler_(&evb_, fd_, this)
    , thread_()
    , file_names_()
    , states_() {
  CHECK(fd_ != -1) << "Failed to inotify_init()";

  CHECK(handler_.registerHandler(folly::EventHandler::EventFlags::READ |
                                 folly::EventHandler::EventFlags::PERSIST));
  thread_ = std::thread([this] {
      if (!folly::setThreadName("FileWatcher")) {
        LOG(ERROR) << "Failed to setThreadName for FileWatcher thread";
      }
      this->evb_.loopForever();
      LOG(INFO) << "Stopping FileWatcher thread...";
    });
}

FileWatcher::~FileWatcher() {
  handler_.unregisterHandler();
  evb_.terminateLoopSoon();
  thread_.join();
  ::close(fd_);
}

bool FileWatcher::AddFile(const std::string& file_name,
                          std::function<void(std::string)> cb) {
  bool ret = true;
  evb_.runInEventBaseThreadAndWait([&ret, &file_name, &cb, this] {
      auto watch_fd = RegisterFile(file_name);
      if (watch_fd == -1) {
        ret = false;
        return;
      }

      uint64_t hash;
      cb(ReadFileAndHash(file_name, &hash));

      file_names_.emplace(watch_fd, file_name);
      states_.emplace(file_name, State(std::move(cb), hash, watch_fd));
    });

  return ret;
}

bool FileWatcher::RemoveFile(const std::string& file_name) {
  bool ret = true;
  evb_.runInEventBaseThreadAndWait([&ret, &file_name, this] {
      auto itor = states_.find(file_name);
      if (itor == states_.end()) {
        LOG(ERROR) << file_name << " is not being watched";
        ret = false;
        return;
      }

      const auto& state = itor->second;
      if (state.watch_fd != -1 &&
          ::inotify_rm_watch(fd_, state.watch_fd) == -1) {
        LOG(ERROR) << " Failed to inotify_rm_watch() with errno " << errno;
        ret = false;
        return;
      }

      file_names_.erase(state.watch_fd);
      states_.erase(itor);
    });

  return ret;
}

void FileWatcher::ReadAndProcessEvents() {
  const int kBufLength = 1024 * (sizeof(struct inotify_event) + 16);
  static char buf[kBufLength];

  auto length = ::read(fd_, buf, kBufLength);
  if (length < 0) {
    LOG(ERROR) << "Failed to read() inotify fd with errno " << errno;
    return;
  }

  ProcessEvents(buf, length);
}

void FileWatcher::ProcessEvents(const char* buf, int sz) {
  // It is promised that there will be no partial or truncated inotify_event
  // structs.
  int i = 0;
  while (i < sz) {
    auto event = reinterpret_cast<const struct inotify_event*>(buf + i);
    i += sizeof(struct inotify_event) + event->len;

    auto file_name_itor = file_names_.find(event->wd);
    if (file_name_itor == file_names_.end()) {
      // this is possible as clients could have removed it from FileWatcher
      continue;
    }
    auto state_itor = states_.find(file_name_itor->second);
    CHECK(state_itor != states_.end()) << "Cound't find state for file "
                                       << file_name_itor->second;

    if (event->mask & (IN_IGNORED | IN_UNMOUNT | IN_MOVE_SELF)) {
      // A watched file has been removed or unmounted, we will need to
      // periodically try to re-register it.
      LOG(ERROR) << "File removed or unmounted: " << file_name_itor->second;
      state_itor->second.watch_fd = -1;
      file_names_.erase(file_name_itor);
      ScheduleRegisterMonitoredFile(state_itor->first);

      continue;
    }

    if ((event->mask & IN_CLOSE_WRITE) == 0) {
      LOG(ERROR) << "Events other than IN_CLOSE_WRITE returned " << event->mask;
      continue;
    }

    auto& state = state_itor->second;
    CheckFileAndCallback(state_itor->first, &state);
  }
}

std::string FileWatcher::ReadFileAndHash(const std::string& file_name,
                                         uint64_t* hash) {
  CHECK(hash);
  std::string content;
  if (!folly::readFile(file_name.c_str(), content)) {
    LOG(ERROR) << "Failed to read file " << file_name << " with errno "
               << errno << " : " << strerror(errno);
    content.clear();
  }

  *hash = folly::hash::SpookyHashV2::Hash64(content.data(), content.size(), 0);
  return content;
}

int FileWatcher::RegisterFile(const std::string& file_name,
                              const bool check_dup) {
  if (check_dup && states_.count(file_name) == 1) {
    LOG(ERROR) << file_name << " is already being watched, RemoveFile() "
               << "first if you want to change its callback.";
    return -1;
  }

  auto watch_fd = ::inotify_add_watch(fd_, file_name.c_str(),
                                      IN_CLOSE_WRITE | IN_MOVE_SELF);
  if (watch_fd == -1) {
    LOG(ERROR) << "Failed to inotify_add_watch() with errno " << errno <<
        " : " << strerror(errno);
  }

  return watch_fd;
}

void FileWatcher::ScheduleRegisterMonitoredFile(const std::string& file_name) {
  LOG(INFO) << "Schedule registering file " << file_name << " in "
            << kRecheckRemovedFileIntervalMs << " ms.";
  try {
    evb_.runAfterDelay([this, file_name] {
      auto itor = states_.find(file_name);
      if (itor == states_.end()) {
        LOG(ERROR) << file_name << " has been removed, cancel registering";
        return;
      }

      auto watch_fd = RegisterFile(file_name, false);
      if (watch_fd == -1) {
        ScheduleRegisterMonitoredFile(file_name);
        return;
      }

      auto& state = itor->second;
      CheckFileAndCallback(file_name, &state);

      file_names_.emplace(watch_fd, std::move(file_name));
      state.watch_fd = watch_fd;
    },
    kRecheckRemovedFileIntervalMs);
  } catch (const std::system_error& err) {
    LOG(ERROR) << "Failed to schedule registering file: " << file_name
               << std::endl << err.what();
    states_.erase(file_name);
  }
}

void FileWatcher::CheckFileAndCallback(const std::string& file_name,
                                       State* state) {
  CHECK(state);
  uint64_t new_hash;
  auto content = ReadFileAndHash(file_name, &new_hash);
  if (new_hash != state->current_hash) {
    state->current_hash = new_hash;
    state->cb(std::move(content));
  }
}
}  // namespace common
<commit_msg>[file_watcher] Add stats around file changes. (#317)<commit_after>/// Copyright 2016 Pinterest Inc.
///
/// 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.

//
// @author bol (bol@pinterest.com)
//

#include "common/file_watcher.h"
#include "common/stats/stats.h"

#include <folly/FileUtil.h>
#include <folly/SpookyHashV2.h>
#include <folly/ThreadName.h>
#include <sys/inotify.h>

#include <string>

#include "boost/filesystem.hpp"
#include "gflags/gflags.h"

/*
 * TODO(shu): Commented temporarily.
 * Reason: In Pinability scorer shared object
 * we want to use file watcher to watch model files. The flag will
 * be defined twice since we both static and dynamic link file watcher.
 * Since this flag is not being set actively, making it a
 * hard coded number for now.
 */
// DEFINE_int32(recheck_removed_file_interval_ms, 2 * 1000,
//              "The interval for checking removed files");
const int kRecheckRemovedFileIntervalMs = 2000;

namespace common {
FileWatcher* FileWatcher::Instance() {
  static FileWatcher instance;
  return &instance;
}

FileWatcher::FileWatcher()
    : evb_()
    , fd_(::inotify_init())
    , handler_(&evb_, fd_, this)
    , thread_()
    , file_names_()
    , states_() {
  CHECK(fd_ != -1) << "Failed to inotify_init()";

  CHECK(handler_.registerHandler(folly::EventHandler::EventFlags::READ |
                                 folly::EventHandler::EventFlags::PERSIST));
  thread_ = std::thread([this] {
      if (!folly::setThreadName("FileWatcher")) {
        LOG(ERROR) << "Failed to setThreadName for FileWatcher thread";
      }
      this->evb_.loopForever();
      LOG(INFO) << "Stopping FileWatcher thread...";
    });
}

FileWatcher::~FileWatcher() {
  handler_.unregisterHandler();
  evb_.terminateLoopSoon();
  thread_.join();
  ::close(fd_);
}

bool FileWatcher::AddFile(const std::string& file_name,
                          std::function<void(std::string)> cb) {
  bool ret = true;
  evb_.runInEventBaseThreadAndWait([&ret, &file_name, &cb, this] {
      auto watch_fd = RegisterFile(file_name);
      if (watch_fd == -1) {
        ret = false;
        return;
      }

      uint64_t hash;
      cb(ReadFileAndHash(file_name, &hash));

      file_names_.emplace(watch_fd, file_name);
      states_.emplace(file_name, State(std::move(cb), hash, watch_fd));
    });

  return ret;
}

bool FileWatcher::RemoveFile(const std::string& file_name) {
  bool ret = true;
  evb_.runInEventBaseThreadAndWait([&ret, &file_name, this] {
      auto itor = states_.find(file_name);
      if (itor == states_.end()) {
        LOG(ERROR) << file_name << " is not being watched";
        ret = false;
        return;
      }

      const auto& state = itor->second;
      if (state.watch_fd != -1 &&
          ::inotify_rm_watch(fd_, state.watch_fd) == -1) {
        LOG(ERROR) << " Failed to inotify_rm_watch() with errno " << errno;
        ret = false;
        return;
      }

      file_names_.erase(state.watch_fd);
      states_.erase(itor);
    });

  return ret;
}

void FileWatcher::ReadAndProcessEvents() {
  const int kBufLength = 1024 * (sizeof(struct inotify_event) + 16);
  static char buf[kBufLength];

  auto length = ::read(fd_, buf, kBufLength);
  if (length < 0) {
    LOG(ERROR) << "Failed to read() inotify fd with errno " << errno;
    return;
  }

  ProcessEvents(buf, length);
}

void FileWatcher::ProcessEvents(const char* buf, int sz) {
  // It is promised that there will be no partial or truncated inotify_event
  // structs.
  int i = 0;
  while (i < sz) {
    auto event = reinterpret_cast<const struct inotify_event*>(buf + i);
    i += sizeof(struct inotify_event) + event->len;

    auto file_name_itor = file_names_.find(event->wd);
    if (file_name_itor == file_names_.end()) {
      // this is possible as clients could have removed it from FileWatcher
      continue;
    }
    auto state_itor = states_.find(file_name_itor->second);
    CHECK(state_itor != states_.end()) << "Cound't find state for file "
                                       << file_name_itor->second;

    if (event->mask & (IN_IGNORED | IN_UNMOUNT | IN_MOVE_SELF)) {
      // A watched file has been removed or unmounted, we will need to
      // periodically try to re-register it.
      LOG(ERROR) << "File removed or unmounted: " << file_name_itor->second;
      state_itor->second.watch_fd = -1;
      file_names_.erase(file_name_itor);
      ScheduleRegisterMonitoredFile(state_itor->first);

      continue;
    }

    if ((event->mask & IN_CLOSE_WRITE) == 0) {
      LOG(ERROR) << "Events other than IN_CLOSE_WRITE returned " << event->mask;
      continue;
    }

    auto& state = state_itor->second;
    CheckFileAndCallback(state_itor->first, &state);
  }
}

std::string FileWatcher::ReadFileAndHash(const std::string& file_name,
                                         uint64_t* hash) {
  CHECK(hash);
  std::string content;
  if (!folly::readFile(file_name.c_str(), content)) {
    LOG(ERROR) << "Failed to read file " << file_name << " with errno "
               << errno << " : " << strerror(errno);
    content.clear();
  }

  *hash = folly::hash::SpookyHashV2::Hash64(content.data(), content.size(), 0);
  return content;
}

int FileWatcher::RegisterFile(const std::string& file_name,
                              const bool check_dup) {
  if (check_dup && states_.count(file_name) == 1) {
    LOG(ERROR) << file_name << " is already being watched, RemoveFile() "
               << "first if you want to change its callback.";
    return -1;
  }

  auto watch_fd = ::inotify_add_watch(fd_, file_name.c_str(),
                                      IN_CLOSE_WRITE | IN_MOVE_SELF);
  if (watch_fd == -1) {
    LOG(ERROR) << "Failed to inotify_add_watch() with errno " << errno <<
        " : " << strerror(errno);
  }

  return watch_fd;
}

void FileWatcher::ScheduleRegisterMonitoredFile(const std::string& file_name) {
  LOG(INFO) << "Schedule registering file " << file_name << " in "
            << kRecheckRemovedFileIntervalMs << " ms.";
  try {
    evb_.runAfterDelay([this, file_name] {
      auto itor = states_.find(file_name);
      if (itor == states_.end()) {
        LOG(ERROR) << file_name << " has been removed, cancel registering";
        return;
      }

      auto watch_fd = RegisterFile(file_name, false);
      if (watch_fd == -1) {
        ScheduleRegisterMonitoredFile(file_name);
        return;
      }

      auto& state = itor->second;
      CheckFileAndCallback(file_name, &state);

      file_names_.emplace(watch_fd, std::move(file_name));
      state.watch_fd = watch_fd;
    },
    kRecheckRemovedFileIntervalMs);
  } catch (const std::system_error& err) {
    LOG(ERROR) << "Failed to schedule registering file: " << file_name
               << std::endl << err.what();
    states_.erase(file_name);
  }
}

void FileWatcher::CheckFileAndCallback(const std::string& file_name,
                                       State* state) {
  CHECK(state);
  uint64_t new_hash;
  auto content = ReadFileAndHash(file_name, &new_hash);
  if (new_hash != state->current_hash) {
    LOG(INFO) << "File change detected for " << file_name;
    common::Stats::get()->Incr("file_change_detected file_name=" +
      boost::filesystem::path(file_name).filename().string());
    state->current_hash = new_hash;
    state->cb(std::move(content));
  }
}
}  // namespace common
<|endoftext|>


<commit_before>#include "QDataAnalysisView.h"
#include "QAction"
#include "QHeaderView"
#include <algorithm>
#include "simvis/color.h"
#include "xo/system/log_sink.h"
#include "xo/utility/types.h"
#include <set>
#include "qtfx.h"
#include <array>
#include "xo/system/log.h"

QDataAnalysisView::QDataAnalysisView( QDataAnalysisModel* m, QWidget* parent ) : QWidget( parent ), model( m ), currentUpdateIdx( 0 )
{
	selectBox = new QCheckBox( this );
	connect( selectBox, &QCheckBox::stateChanged, this, &QDataAnalysisView::select );

	filter = new QLineEdit( this );
	connect( filter, &QLineEdit::textChanged, this, &QDataAnalysisView::filterChanged );

	auto* header = new QHGroup( this, 0, 4 );
	*header << new QLabel( "Filter", this ) << filter << selectBox;

	itemList = new QTreeWidget( this );
	itemList->setRootIsDecorated( false );
	itemList->setColumnCount( 2 );
	itemList->header()->close();
	itemList->resize( 100, 100 );
	QStringList headerLabels;
	headerLabels << "Variable" << "Value";
	itemList->setHeaderLabels( headerLabels );

	itemGroup = new QVGroup( this, 0, 4 );
	*itemGroup << header << itemList;
	connect( itemList, &QTreeWidget::itemChanged, this, &QDataAnalysisView::itemChanged );

	splitter = new QSplitter( this );
	splitter->setContentsMargins( 0, 0, 0, 0 );
	splitter->setObjectName( "Analysis.Splitter" );
	splitter->addWidget( itemGroup );

	QVBoxLayout* layout = new QVBoxLayout( this );
	layout->setContentsMargins( 2, 0, 2, 0 );
	layout->setSpacing( 4 );
	layout->addWidget( splitter );

#if !defined QTFX_NO_QCUSTOMPLOT
	customPlot = new QCustomPlot();
	customPlot->setInteraction( QCP::iRangeZoom, true );
	customPlot->setInteraction( QCP::iRangeDrag, true );
	customPlot->axisRect()->setRangeDrag( Qt::Horizontal );
	customPlot->axisRect()->setRangeZoom( Qt::Horizontal );
	customPlot->legend->setVisible( true );
	customPlot->legend->setFont( itemList->font() );
	customPlot->legend->setRowSpacing( -6 );
	customPlotLine = new QCPItemLine( customPlot );
	customPlotLine->setHead( QCPLineEnding( QCPLineEnding::esDiamond, 9, 9, true ) );
	customPlotLine->setTail( QCPLineEnding( QCPLineEnding::esDiamond, 9, 9, true ) );
	customPlot->addItem( customPlotLine );
	splitter->addWidget( customPlot );
	connect( customPlot, &QCustomPlot::mousePress, this, &QDataAnalysisView::mouseEvent );
	connect( customPlot, &QCustomPlot::mouseMove, this, &QDataAnalysisView::mouseEvent );
	connect( customPlot->xAxis, SIGNAL( rangeChanged( const QCPRange&, const QCPRange& ) ), this, SLOT( rangeChanged( const QCPRange&, const QCPRange& ) ) );

#else
	chart = new QtCharts::QChart();
	chart->setBackgroundRoundness( 0 );
	chart->setMargins( QMargins( 4, 4, 4, 4 ) );
	chart->layout()->setContentsMargins( 0, 0, 0, 0 );
	chart->legend()->setAlignment( Qt::AlignRight );
	chart->createDefaultAxes();
	chartView = new QtCharts::QChartView( chart, this );
	chartView->setContentsMargins( 0, 0, 0, 0 );
	chartView->setRenderHint( QPainter::Antialiasing );
	chartView->setRubberBand( QtCharts::QChartView::RectangleRubberBand );
	chartView->setBackgroundBrush( QBrush( Qt::red ) );
	chartView->resize( 300, 100 );
	splitter->addWidget( chartView );
#endif

	splitter->setSizes( QList< int >{ 100, 300 } );
	reset();
}

void QDataAnalysisView::refresh( double time, bool refreshAll )
{
	if ( itemList->topLevelItemCount() != model->getSeriesCount() )
		return reset();

	if ( model->getSeriesCount() == 0 )
		return;

	// update state
	currentTime = time;

	// draw stuff if visible
	if ( isVisible() )
	{
		int itemCount = refreshAll ? model->getSeriesCount() : std::min<int>( smallRefreshItemCount, model->getSeriesCount() );
		itemList->setUpdatesEnabled( false );
		for ( size_t i = 0; i < itemCount; ++i )
		{
			itemList->topLevelItem( currentUpdateIdx )->setText( 1, QString().sprintf( "%.3f", model->getValue( currentUpdateIdx, time ) ) );
			++currentUpdateIdx %= model->getSeriesCount();
		}
		itemList->setUpdatesEnabled( true );

		// update graph
		updateIndicator();

#ifdef QTFX_USE_QCUSTOMPLOT
		customPlot->replot( QCustomPlot::rpQueued );
#endif
	}
}

void QDataAnalysisView::itemChanged( QTreeWidgetItem* item, int column )
{
	if ( column == 0 )
		updateSeries( itemList->indexOfTopLevelItem( item ) );
}

void QDataAnalysisView::clearSeries()
{
	while ( !series.empty() )
		removeSeries( series.rbegin()->first );
}

void QDataAnalysisView::mouseEvent( QMouseEvent* event )
{
#if !defined QTFX_NO_QCUSTOMPLOT
	if ( event->buttons() & Qt::LeftButton )
	{
		double x = customPlot->xAxis->pixelToCoord( event->pos().x() );
		xo::clamp( x, model->getTimeStart(), model->getTimeFinish() );
		emit timeChanged( x );
	}
#endif
}

void QDataAnalysisView::rangeChanged( const QCPRange &newRange, const QCPRange &oldRange )
{
	auto newZoom = currentSeriesInterval * customPlot->xAxis->axisRect()->width() / newRange.size();
	auto oldZoom = currentSeriesInterval * customPlot->xAxis->axisRect()->width() / oldRange.size();
	if ( ( newZoom > 5 && oldZoom <= 5 ) || ( oldZoom > 5 && newZoom <= 5 ) )
		refreshSeriesStyle();
}

void QDataAnalysisView::filterChanged( const QString& filter )
{
	updateFilter();
}

void QDataAnalysisView::setSelectionState( int state )
{
	if ( state != Qt::PartiallyChecked )
	{
		for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
		{
			auto* item = itemList->topLevelItem( i );
			if ( !item->isHidden() && item->checkState( 0 ) != state )
				item->setCheckState( 0, Qt::CheckState( state ) );
		}
	}
}

QColor QDataAnalysisView::getStandardColor( int idx, float value )
{
	static std::array< float, 10 > standard_hue{ 0, 60, 120, 180, 240, 300, 30, 210, 270, 330 };
	static std::array< float, 10 > standard_val{ 1, 0.75, 0.75, 0.75, 1, 1, 1, 0.75, 1, 1 };
	float hue = standard_hue[ idx % standard_hue.size() ];
	float sat = 1.0f / ( 1.0f + idx / standard_hue.size() );
	float val = standard_val[ idx % standard_hue.size() ];
	vis::color c = vis::make_from_hsv( hue, sat, val );
	return QColor( 255 * c.r, 255 * c.g, 255 * c.b );
}

void QDataAnalysisView::reset()
{
	// remove series, keep names
	std::set< QString > keep_series;
	for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
	{
		auto* item = itemList->topLevelItem( i );
		if ( item->checkState( 0 ) == Qt::Checked )
			keep_series.insert( item->text( 0 ) );
	}

	itemList->clear();
	clearSeries();

	for ( size_t i = 0; i < model->getSeriesCount(); ++i )
	{
		auto* wdg = new QTreeWidgetItem( itemList, QStringList( model->getLabel( i ) ) );
		wdg->setTextAlignment( 1, Qt::AlignRight );
		wdg->setFlags( wdg->flags() | Qt::ItemIsUserCheckable );
		wdg->setCheckState( 0, keep_series.count( model->getLabel( i ) ) > 0 ? Qt::Checked : Qt::Unchecked );
	}
	itemList->resizeColumnToContents( 0 );

	currentUpdateIdx = 0;
	currentTime = 0.0;
	updateIndicator();
	updateFilter();
}

void QDataAnalysisView::updateIndicator()
{
#if !defined QTFX_NO_QCUSTOMPLOT
	customPlotLine->start->setCoords( currentTime, customPlot->yAxis->range().lower );
	customPlotLine->end->setCoords( currentTime, customPlot->yAxis->range().upper );
	customPlot->replot();
#else
	auto pos = chart->mapToPosition( QPointF( currentTime, 0 ) );
#endif
}

void QDataAnalysisView::updateFilter()
{
	//selectAllButton->setDisabled( filter->text().isEmpty() );
	for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
	{
		auto* item = itemList->topLevelItem( i );
		item->setHidden( !item->text( 0 ).contains( filter->text() ) );
	}

	updateSelectBox();
}

void QDataAnalysisView::updateSelectBox()
{
	size_t checked_count = 0;
	size_t shown_count = 0;

	for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
	{
		auto* item = itemList->topLevelItem( i );
		if ( !item->isHidden() )
		{
			shown_count++;
			checked_count += item->checkState( 0 ) == Qt::Checked;
		}
	}

	selectBox->blockSignals( true );
	selectBox->setCheckState( checked_count > 0 ? ( shown_count == checked_count ? Qt::Checked : Qt::Checked ) : Qt::Unchecked );
	selectBox->blockSignals( false );
}

void QDataAnalysisView::refreshSeriesStyle()
{
	auto zoom = currentSeriesInterval * customPlot->xAxis->axisRect()->width() / customPlot->xAxis->range().size();
	QCPScatterStyle ss = QCPScatterStyle( zoom > 5 ? QCPScatterStyle::ssDisc : QCPScatterStyle::ssNone, 5 );

	int i = 0;
	for ( auto& s : series )
	{
		s.second->setPen( QPen( getStandardColor( i++ ) ) );
		s.second->setScatterStyle( ss );
		s.second->setLineStyle( QCPGraph::lsLine );
	}
}

void QDataAnalysisView::updateSeries( int idx )
{
	auto item = itemList->topLevelItem( idx );
	auto series_it = series.find( idx );
	if ( item->checkState( 0 ) == Qt::Checked && series_it == series.end() )
	{
		if ( series.size() < maxSeriesCount )
			addSeries( idx );
		else item->setCheckState( 0, Qt::Unchecked );
	}
	else if ( series_it != series.end() && item->checkState( 0 ) == Qt::Unchecked )
	{
		removeSeries( idx );
	}
	updateSelectBox();
}

void QDataAnalysisView::addSeries( int idx )
{
#if !defined QTFX_NO_QCUSTOMPLOT
	QCPGraph* graph = customPlot->addGraph();
	graph->setName( model->getLabel( idx ) );
	auto data = model->getSeries( idx, minSeriesInterval );
	for ( auto& e : data )
		graph->addData( e.first, e.second );
	series[ idx ] = graph;
	currentSeriesInterval = ( data.back().first - data.front().first ) / data.size();

	refreshSeriesStyle();

	auto range = customPlot->xAxis->range();
	customPlot->rescaleAxes();
	customPlot->xAxis->setRange( range );
	updateIndicator();
	customPlot->replot();
#else
	QtCharts::QLineSeries* ls = new QtCharts::QLineSeries;
	ls->setName( model->getLabel( idx ) );
	auto data = model->getSeries( idx, minSeriesInterval );
	for ( auto& e : data )
		ls->append( e.first, e.second );
	chart->addSeries( ls );
	chart->createDefaultAxes();
	chart->zoomReset();
	series[ idx ] = ls;
#endif
}

void QDataAnalysisView::removeSeries( int idx )
{
#if !defined QTFX_NO_QCUSTOMPLOT
	auto range = customPlot->xAxis->range();
	auto it = series.find( idx );

	customPlot->removeGraph( it->second );
	series.erase( it );

	customPlot->rescaleAxes();
	customPlot->xAxis->setRange( range );
	updateIndicator();
	customPlot->replot();
#else
	auto it = series.find( idx );
	chart->removeSeries( it->second );
	chart->zoomReset();
	chart->createDefaultAxes();
	series.erase( it );
#endif
}
<commit_msg>tightened margins even more<commit_after>#include "QDataAnalysisView.h"
#include "QAction"
#include "QHeaderView"
#include <algorithm>
#include "simvis/color.h"
#include "xo/system/log_sink.h"
#include "xo/utility/types.h"
#include <set>
#include "qtfx.h"
#include <array>
#include "xo/system/log.h"

QDataAnalysisView::QDataAnalysisView( QDataAnalysisModel* m, QWidget* parent ) : QWidget( parent ), model( m ), currentUpdateIdx( 0 )
{
	selectBox = new QCheckBox( this );
	connect( selectBox, &QCheckBox::stateChanged, this, &QDataAnalysisView::select );

	filter = new QLineEdit( this );
	connect( filter, &QLineEdit::textChanged, this, &QDataAnalysisView::filterChanged );

	auto* header = new QHGroup( this, 0, 4 );
	*header << new QLabel( "Filter", this ) << filter << selectBox;

	itemList = new QTreeWidget( this );
	itemList->setRootIsDecorated( false );
	itemList->setColumnCount( 2 );
	itemList->header()->close();
	itemList->resize( 100, 100 );
	QStringList headerLabels;
	headerLabels << "Variable" << "Value";
	itemList->setHeaderLabels( headerLabels );

	itemGroup = new QVGroup( this, 0, 4 );
	itemGroup->setContentsMargins( 0, 0, 0, 0 );
	*itemGroup << header << itemList;
	connect( itemList, &QTreeWidget::itemChanged, this, &QDataAnalysisView::itemChanged );

	splitter = new QSplitter( this );
	splitter->setContentsMargins( 0, 0, 0, 0 );
	splitter->setObjectName( "Analysis.Splitter" );
	splitter->addWidget( itemGroup );

	QVBoxLayout* layout = new QVBoxLayout( this );
	layout->setContentsMargins( 0, 0, 0, 0 );
	layout->setSpacing( 4 );
	layout->addWidget( splitter );

#if !defined QTFX_NO_QCUSTOMPLOT
	customPlot = new QCustomPlot();
	customPlot->setInteraction( QCP::iRangeZoom, true );
	customPlot->setInteraction( QCP::iRangeDrag, true );
	customPlot->axisRect()->setRangeDrag( Qt::Horizontal );
	customPlot->axisRect()->setRangeZoom( Qt::Horizontal );
	customPlot->legend->setVisible( true );
	customPlot->legend->setFont( itemList->font() );
	customPlot->legend->setRowSpacing( -6 );
	customPlotLine = new QCPItemLine( customPlot );
	customPlotLine->setHead( QCPLineEnding( QCPLineEnding::esDiamond, 9, 9, true ) );
	customPlotLine->setTail( QCPLineEnding( QCPLineEnding::esDiamond, 9, 9, true ) );
	customPlot->addItem( customPlotLine );
	splitter->addWidget( customPlot );
	connect( customPlot, &QCustomPlot::mousePress, this, &QDataAnalysisView::mouseEvent );
	connect( customPlot, &QCustomPlot::mouseMove, this, &QDataAnalysisView::mouseEvent );
	connect( customPlot->xAxis, SIGNAL( rangeChanged( const QCPRange&, const QCPRange& ) ), this, SLOT( rangeChanged( const QCPRange&, const QCPRange& ) ) );

#else
	chart = new QtCharts::QChart();
	chart->setBackgroundRoundness( 0 );
	chart->setMargins( QMargins( 4, 4, 4, 4 ) );
	chart->layout()->setContentsMargins( 0, 0, 0, 0 );
	chart->legend()->setAlignment( Qt::AlignRight );
	chart->createDefaultAxes();
	chartView = new QtCharts::QChartView( chart, this );
	chartView->setContentsMargins( 0, 0, 0, 0 );
	chartView->setRenderHint( QPainter::Antialiasing );
	chartView->setRubberBand( QtCharts::QChartView::RectangleRubberBand );
	chartView->setBackgroundBrush( QBrush( Qt::red ) );
	chartView->resize( 300, 100 );
	splitter->addWidget( chartView );
#endif

	splitter->setSizes( QList< int >{ 100, 300 } );
	reset();
}

void QDataAnalysisView::refresh( double time, bool refreshAll )
{
	if ( itemList->topLevelItemCount() != model->getSeriesCount() )
		return reset();

	if ( model->getSeriesCount() == 0 )
		return;

	// update state
	currentTime = time;

	// draw stuff if visible
	if ( isVisible() )
	{
		int itemCount = refreshAll ? model->getSeriesCount() : std::min<int>( smallRefreshItemCount, model->getSeriesCount() );
		itemList->setUpdatesEnabled( false );
		for ( size_t i = 0; i < itemCount; ++i )
		{
			itemList->topLevelItem( currentUpdateIdx )->setText( 1, QString().sprintf( "%.3f", model->getValue( currentUpdateIdx, time ) ) );
			++currentUpdateIdx %= model->getSeriesCount();
		}
		itemList->setUpdatesEnabled( true );

		// update graph
		updateIndicator();

#ifdef QTFX_USE_QCUSTOMPLOT
		customPlot->replot( QCustomPlot::rpQueued );
#endif
	}
}

void QDataAnalysisView::itemChanged( QTreeWidgetItem* item, int column )
{
	if ( column == 0 )
		updateSeries( itemList->indexOfTopLevelItem( item ) );
}

void QDataAnalysisView::clearSeries()
{
	while ( !series.empty() )
		removeSeries( series.rbegin()->first );
}

void QDataAnalysisView::mouseEvent( QMouseEvent* event )
{
#if !defined QTFX_NO_QCUSTOMPLOT
	if ( event->buttons() & Qt::LeftButton )
	{
		double x = customPlot->xAxis->pixelToCoord( event->pos().x() );
		xo::clamp( x, model->getTimeStart(), model->getTimeFinish() );
		emit timeChanged( x );
	}
#endif
}

void QDataAnalysisView::rangeChanged( const QCPRange &newRange, const QCPRange &oldRange )
{
	auto newZoom = currentSeriesInterval * customPlot->xAxis->axisRect()->width() / newRange.size();
	auto oldZoom = currentSeriesInterval * customPlot->xAxis->axisRect()->width() / oldRange.size();
	if ( ( newZoom > 5 && oldZoom <= 5 ) || ( oldZoom > 5 && newZoom <= 5 ) )
		refreshSeriesStyle();
}

void QDataAnalysisView::filterChanged( const QString& filter )
{
	updateFilter();
}

void QDataAnalysisView::setSelectionState( int state )
{
	if ( state != Qt::PartiallyChecked )
	{
		for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
		{
			auto* item = itemList->topLevelItem( i );
			if ( !item->isHidden() && item->checkState( 0 ) != state )
				item->setCheckState( 0, Qt::CheckState( state ) );
		}
	}
}

QColor QDataAnalysisView::getStandardColor( int idx, float value )
{
	static std::array< float, 10 > standard_hue{ 0, 60, 120, 180, 240, 300, 30, 210, 270, 330 };
	static std::array< float, 10 > standard_val{ 1, 0.75, 0.75, 0.75, 1, 1, 1, 0.75, 1, 1 };
	float hue = standard_hue[ idx % standard_hue.size() ];
	float sat = 1.0f / ( 1.0f + idx / standard_hue.size() );
	float val = standard_val[ idx % standard_hue.size() ];
	vis::color c = vis::make_from_hsv( hue, sat, val );
	return QColor( 255 * c.r, 255 * c.g, 255 * c.b );
}

void QDataAnalysisView::reset()
{
	// remove series, keep names
	std::set< QString > keep_series;
	for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
	{
		auto* item = itemList->topLevelItem( i );
		if ( item->checkState( 0 ) == Qt::Checked )
			keep_series.insert( item->text( 0 ) );
	}

	itemList->clear();
	clearSeries();

	for ( size_t i = 0; i < model->getSeriesCount(); ++i )
	{
		auto* wdg = new QTreeWidgetItem( itemList, QStringList( model->getLabel( i ) ) );
		wdg->setTextAlignment( 1, Qt::AlignRight );
		wdg->setFlags( wdg->flags() | Qt::ItemIsUserCheckable );
		wdg->setCheckState( 0, keep_series.count( model->getLabel( i ) ) > 0 ? Qt::Checked : Qt::Unchecked );
	}
	itemList->resizeColumnToContents( 0 );

	currentUpdateIdx = 0;
	currentTime = 0.0;
	updateIndicator();
	updateFilter();
}

void QDataAnalysisView::updateIndicator()
{
#if !defined QTFX_NO_QCUSTOMPLOT
	customPlotLine->start->setCoords( currentTime, customPlot->yAxis->range().lower );
	customPlotLine->end->setCoords( currentTime, customPlot->yAxis->range().upper );
	customPlot->replot();
#else
	auto pos = chart->mapToPosition( QPointF( currentTime, 0 ) );
#endif
}

void QDataAnalysisView::updateFilter()
{
	//selectAllButton->setDisabled( filter->text().isEmpty() );
	for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
	{
		auto* item = itemList->topLevelItem( i );
		item->setHidden( !item->text( 0 ).contains( filter->text() ) );
	}

	updateSelectBox();
}

void QDataAnalysisView::updateSelectBox()
{
	size_t checked_count = 0;
	size_t shown_count = 0;

	for ( size_t i = 0; i < itemList->topLevelItemCount(); ++i )
	{
		auto* item = itemList->topLevelItem( i );
		if ( !item->isHidden() )
		{
			shown_count++;
			checked_count += item->checkState( 0 ) == Qt::Checked;
		}
	}

	selectBox->blockSignals( true );
	selectBox->setCheckState( checked_count > 0 ? ( shown_count == checked_count ? Qt::Checked : Qt::Checked ) : Qt::Unchecked );
	selectBox->blockSignals( false );
}

void QDataAnalysisView::refreshSeriesStyle()
{
	auto zoom = currentSeriesInterval * customPlot->xAxis->axisRect()->width() / customPlot->xAxis->range().size();
	QCPScatterStyle ss = QCPScatterStyle( zoom > 5 ? QCPScatterStyle::ssDisc : QCPScatterStyle::ssNone, 5 );

	int i = 0;
	for ( auto& s : series )
	{
		s.second->setPen( QPen( getStandardColor( i++ ) ) );
		s.second->setScatterStyle( ss );
		s.second->setLineStyle( QCPGraph::lsLine );
	}
}

void QDataAnalysisView::updateSeries( int idx )
{
	auto item = itemList->topLevelItem( idx );
	auto series_it = series.find( idx );
	if ( item->checkState( 0 ) == Qt::Checked && series_it == series.end() )
	{
		if ( series.size() < maxSeriesCount )
			addSeries( idx );
		else item->setCheckState( 0, Qt::Unchecked );
	}
	else if ( series_it != series.end() && item->checkState( 0 ) == Qt::Unchecked )
	{
		removeSeries( idx );
	}
	updateSelectBox();
}

void QDataAnalysisView::addSeries( int idx )
{
#if !defined QTFX_NO_QCUSTOMPLOT
	QCPGraph* graph = customPlot->addGraph();
	graph->setName( model->getLabel( idx ) );
	auto data = model->getSeries( idx, minSeriesInterval );
	for ( auto& e : data )
		graph->addData( e.first, e.second );
	series[ idx ] = graph;
	currentSeriesInterval = ( data.back().first - data.front().first ) / data.size();

	refreshSeriesStyle();

	auto range = customPlot->xAxis->range();
	customPlot->rescaleAxes();
	customPlot->xAxis->setRange( range );
	updateIndicator();
	customPlot->replot();
#else
	QtCharts::QLineSeries* ls = new QtCharts::QLineSeries;
	ls->setName( model->getLabel( idx ) );
	auto data = model->getSeries( idx, minSeriesInterval );
	for ( auto& e : data )
		ls->append( e.first, e.second );
	chart->addSeries( ls );
	chart->createDefaultAxes();
	chart->zoomReset();
	series[ idx ] = ls;
#endif
}

void QDataAnalysisView::removeSeries( int idx )
{
#if !defined QTFX_NO_QCUSTOMPLOT
	auto range = customPlot->xAxis->range();
	auto it = series.find( idx );

	customPlot->removeGraph( it->second );
	series.erase( it );

	customPlot->rescaleAxes();
	customPlot->xAxis->setRange( range );
	updateIndicator();
	customPlot->replot();
#else
	auto it = series.find( idx );
	chart->removeSeries( it->second );
	chart->zoomReset();
	chart->createDefaultAxes();
	series.erase( it );
#endif
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	固定サイズ文字列クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <algorithm>
#include <cstring>

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  固定サイズ文字列クラス
		@param[in]	SIZE	文字列サイズ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t SIZE>
	class fixed_string {
		char		text_[SIZE];
		uint32_t	pos_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクタ
			@param[in]	str	初期設定文字列
		*/
		//-----------------------------------------------------------------//
		fixed_string(const char* str = nullptr) noexcept : pos_(0) {
			if(str != nullptr) {
				std::strcpy(text_, str);
				pos_ = std::strlen(text_);
			} else {
				text_[pos_] = 0;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  格納可能な最大サイズを返す（終端の数を除外）
			@return 格納可能な最大サイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t capacity() const noexcept { return SIZE - 1; }

		//-----------------------------------------------------------------//
		/*!
			@brief  現在のサイズを返す
			@return 現在のサイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t size() const noexcept { return pos_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列をクリア（リセット）
		*/
		//-----------------------------------------------------------------//
		void clear() noexcept {
			pos_ = 0;
			text_[pos_] = 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列を返す
			@return 文字列
		*/
		//-----------------------------------------------------------------//
		const char* c_str() const noexcept { return text_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  交換
			@param[in]	src	ソース
			@return 自分
		*/
		//-----------------------------------------------------------------//
		void swap(fixed_string& src) noexcept {
			std::swap(src.text_, text_);
			std::swap(src.pos_, pos_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  代入
			@param[in]	src	ソース
			@return 自分
		*/
		//-----------------------------------------------------------------//
		fixed_string& operator = (const fixed_string& src) {
			std::strcpy(text_, src.c_str());
			pos_ = src.pos_;
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字を追加
			@param[in]	ch	文字
			@return 自分
		*/
		//-----------------------------------------------------------------//
		fixed_string& operator += (char ch) {
			if(pos_ < (SIZE - 1)) {
				text_[pos_] = ch;
				++pos_;
				text_[pos_] = 0;
			}
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列を追加
			@param[in]	str	文字列
			@return 自分
		*/
		//-----------------------------------------------------------------//
		fixed_string& operator += (const char* str) {
			if(str == nullptr) {
				return *this;
			}

			uint32_t l = std::strlen(str);
			if((pos_ + l) < (SIZE - 1)) {
				std::strcpy(&text_[pos_], str);
				pos_ += l;
			} else {  // バッファが許す範囲でコピー
				l = SIZE - pos_ - 1;
				std::strncpy(&text_[pos_], str, l);
				pos_ = SIZE - 1;
			}
			text_[pos_] = 0;
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字参照
			@param[in]	pos	配列位置
			@return 文字
		*/
		//-----------------------------------------------------------------//
		char& operator [] (uint32_t pos) noexcept {
			if(pos >= pos_) {
				static char tmp = 0;
				return tmp;
			}
			return text_[pos];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  一致比較
			@param[in]	text	文字列
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool cmp(const char* text) const noexcept {
			if(text == nullptr) {
				return pos_ == 0;
			}
			return std::strcmp(c_str(), text) == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  一致比較（オペレーター）
			@param[in]	text	文字列
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator == (const char* text) const { return cmp(text); }

		//-----------------------------------------------------------------//
		/*!
			@brief  不一致比較（オペレーター）
			@param[in]	text	文字列
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator != (const char* text) const { return !cmp(text); }

		//-----------------------------------------------------------------//
		/*!
			@brief  クラス、一致比較（オペレーター）
			@param[in]	th	比較対象
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator == (const fixed_string& th) const {
			return std::strcmp(c_str(), th.c_str()) == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  クラス、不一致比較（オペレーター）
			@param[in]	th	比較対象
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator != (const fixed_string& th) const {
			return std::strcmp(c_str(), th.c_str()) != 0;
		}
	};
}
<commit_msg>update: buffer manage<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	固定サイズ文字列クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <algorithm>
#include <cstring>

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  固定サイズ文字列クラス
		@param[in]	SIZE	文字列サイズ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t SIZE>
	class fixed_string {
		uint32_t	pos_;
		char		text_[SIZE + 1];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクタ
			@param[in]	str	初期設定文字列
		*/
		//-----------------------------------------------------------------//
		fixed_string(const char* str = nullptr) noexcept : pos_(0) {
			if(str != nullptr) {
				std::strncpy(text_, str, SIZE);
				pos_ = std::strlen(text_);
			}
			text_[pos_] = 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  格納可能な最大サイズを返す（終端の数を除外）
			@return 格納可能な最大サイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t capacity() const noexcept { return SIZE; }

		//-----------------------------------------------------------------//
		/*!
			@brief  現在のサイズを返す
			@return 現在のサイズ
		*/
		//-----------------------------------------------------------------//
		uint32_t size() const noexcept { return pos_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列をクリア（リセット）
		*/
		//-----------------------------------------------------------------//
		void clear() noexcept {
			pos_ = 0;
			text_[pos_] = 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列を返す
			@return 文字列
		*/
		//-----------------------------------------------------------------//
		const char* c_str() const noexcept { return text_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  交換
			@param[in]	src	ソース
			@return 自分
		*/
		//-----------------------------------------------------------------//
		void swap(fixed_string& src) noexcept {
			std::swap(src.text_, text_);
			std::swap(src.pos_, pos_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  代入
			@param[in]	src	ソース
			@return 自分
		*/
		//-----------------------------------------------------------------//
		fixed_string& operator = (const fixed_string& src) {
			std::strncpy(text_, src.c_str(), SIZE);
			pos_ = src.pos_;
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字を追加
			@param[in]	ch	文字
			@return 自分
		*/
		//-----------------------------------------------------------------//
		fixed_string& operator += (char ch) {
			if(pos_ < SIZE) {
				text_[pos_] = ch;
				++pos_;
				text_[pos_] = 0;
			}
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字列を追加
			@param[in]	str	文字列
			@return 自分
		*/
		//-----------------------------------------------------------------//
		fixed_string& operator += (const char* str) {
			if(str == nullptr) {
				return *this;
			}

			uint32_t l = std::strlen(str);
			if((pos_ + l) < SIZE) {
				std::strcpy(&text_[pos_], str);
				pos_ += l;
			} else {  // バッファが許す範囲でコピー
				l = SIZE - pos_;
				std::strncpy(&text_[pos_], str, l);
				pos_ = SIZE;
			}
			text_[pos_] = 0;
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  文字参照
			@param[in]	pos	配列位置
			@return 文字
		*/
		//-----------------------------------------------------------------//
		char& operator [] (uint32_t pos) noexcept {
			if(pos >= SIZE) {
				static char tmp = 0;
				return tmp;
			}
			return text_[pos];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  一致比較
			@param[in]	text	文字列
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool cmp(const char* text) const noexcept {
			if(text == nullptr) {
				return pos_ == 0;
			}
			return std::strcmp(c_str(), text) == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  一致比較（オペレーター）
			@param[in]	text	文字列
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator == (const char* text) const { return cmp(text); }

		//-----------------------------------------------------------------//
		/*!
			@brief  不一致比較（オペレーター）
			@param[in]	text	文字列
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator != (const char* text) const { return !cmp(text); }

		//-----------------------------------------------------------------//
		/*!
			@brief  クラス、一致比較（オペレーター）
			@param[in]	th	比較対象
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator == (const fixed_string& th) const {
			return std::strcmp(c_str(), th.c_str()) == 0;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  クラス、不一致比較（オペレーター）
			@param[in]	th	比較対象
			@return 同じなら「true」
		*/
		//-----------------------------------------------------------------//
		bool operator != (const fixed_string& th) const {
			return std::strcmp(c_str(), th.c_str()) != 0;
		}
	};
}
<|endoftext|>


<commit_before>#include <mos/render/material.hpp>
#include <fstream>
#include <json.hpp>
#include <mos/util.hpp>
namespace mos {
  using namespace nlohmann;
  Material::Material(const SharedTexture &texture,
                     const SharedTexture &normalmap, const glm::vec3 &ambient, const glm::vec3 &diffuse,
                   const glm::vec3 &specular, const float opacity,
                   const float specular_exponent)
    : texture(texture), normalmap(normalmap), ambient(ambient), diffuse(diffuse), specular(specular), opacity(opacity),
      specular_exponent(specular_exponent) {}

  Material::Material(const std::string &directory, const std::string &path) {
    if (path.substr(path.find_last_of(".") + 1) == "material") {
      /*std::ifstream is(path, std::ios::binary);
      is.read((char *)&ambient, sizeof(glm::vec3));
      is.read((char *)&diffuse, sizeof(glm::vec3));
      is.read((char *)&specular, sizeof(glm::vec3));
      is.read((char *)&opacity, sizeof(float));
      is.read((char *)&specular_exponent, sizeof(float));*/

      auto value = json::parse(mos::text(directory + '/' + path));
      texture = Texture::load(directory + '/' + value.value("texture", ""));
      normalmap = Texture::load(directory + '/' + value.value("normalmap", ""));
      ambient = glm::vec3(value["ambient"][0], value["ambient"][1], value["ambient"][2]);
      diffuse = glm::vec3(value["diffuse"][0], value["diffuse"][1], value["diffuse"][2]);
      specular = glm::vec3(value["specular"][0], value["specular"][1], value["specular"][2]);
      opacity = value["opacity"];
      specular_exponent = value["specular_exponent"];

    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
                               " file format is not supported.");
    }
  }

  Material::~Material() {}

  SharedMaterial Material::load(const std::string &directory, const std::string &path) {
    if (path.empty() || (path.back() == '/')) {
      return std::make_shared<Material>();
    }
    return std::make_shared<Material>(directory, path);
  }
}
<commit_msg>Kind of working.<commit_after>#include <mos/render/material.hpp>
#include <fstream>
#include <json.hpp>
#include <mos/util.hpp>
#include <string>
namespace mos {
  using namespace nlohmann;
  Material::Material(const SharedTexture &texture,
                     const SharedTexture &normalmap, const glm::vec3 &ambient, const glm::vec3 &diffuse,
                   const glm::vec3 &specular, const float opacity,
                   const float specular_exponent)
    : texture(texture), normalmap(normalmap), ambient(ambient), diffuse(diffuse), specular(specular), opacity(opacity),
      specular_exponent(specular_exponent) {}

  Material::Material(const std::string &directory, const std::string &path) {
    if (path.substr(path.find_last_of(".") + 1) == "material") {
      /*std::ifstream is(path, std::ios::binary);
      is.read((char *)&ambient, sizeof(glm::vec3));
      is.read((char *)&diffuse, sizeof(glm::vec3));
      is.read((char *)&specular, sizeof(glm::vec3));
      is.read((char *)&opacity, sizeof(float));
      is.read((char *)&specular_exponent, sizeof(float));*/

      auto value = json::parse(mos::text(directory + path));
      std::string t = "";
      if (!value["texture"].is_null()){
        t = value["texture"];
      }
      texture = Texture::load(directory + t);
      std::string n = "";
      if (!value["normalmap"].is_null()){
        n = value["normalmap"];
      }
      normalmap = Texture::load(directory + n);
      ambient = glm::vec3(value["ambient"][0], value["ambient"][1], value["ambient"][2]);
      diffuse = glm::vec3(value["diffuse"][0], value["diffuse"][1], value["diffuse"][2]);
      specular = glm::vec3(value["specular"][0], value["specular"][1], value["specular"][2]);
      opacity = value["opacity"];
      specular_exponent = value["specular_exponent"];

    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
                               " file format is not supported.");
    }
  }

  Material::~Material() {}

  SharedMaterial Material::load(const std::string &directory, const std::string &path) {
    if (path.empty() || (path.back() == '/')) {
      return std::make_shared<Material>();
    }
    return std::make_shared<Material>(directory, path);
  }
}
<|endoftext|>


<commit_before>// MS WARNINGS MACRO
#define _SCL_SECURE_NO_WARNINGS

#include <future>
#include <memory>
#include <unordered_map>
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/network.hpp>
#include <boost/range/algorithm.hpp>
#include "network.hpp"

namespace network
{
    // RFC2396 の非予約文字のみエンコード．
    // .NET 4.0以前の EscapeDataString 相当のエンコードを行う．
    template<typename InputIterator, typename OutputIterator>
    OutputIterator client::urlencode(InputIterator first, InputIterator last, OutputIterator out) const
    {
        while(first != last)
        {
            if(
                (0x30<=*first && *first<=0x39) ||
                (0x41<=*first && *first<=0x5a) ||
                (0x61<=*first && *first<=0x7a) ||
                *first==0x21 ||
                *first==0x27 ||
                *first==0x28 ||
                *first==0x29 ||
                *first==0x2a ||
                *first==0x2d ||
                *first==0x2e ||
                *first==0x5f ||
                *first==0x7e
                )
            {
                *out++ = *first++;
            }
            else
            {
                std::string ss((boost::format("%%%02X") % (*first++ & 0xff)).str());
                out = std::copy(ss.begin(), ss.end(), out);
            }
        }
        return out;
    }

    std::string client::urlencode(std::string const& src) const
    {
        std::string ret;
        urlencode(src.cbegin(), src.cend(), std::back_inserter(ret));
        return ret;
    }

    std::string client::form_urlencode(std::unordered_map<std::string, std::string> const& header) const
    {
        std::string ret;

        for(auto const pair : header)
        {
            ret.append(urlencode(pair.first));
            ret.push_back('=');
            ret.append(urlencode(pair.second));
            ret.push_back('&');
        }
        ret.pop_back();

        return ret;
    }

    std::string client::http_request(std::string const url, std::string const request_body)
    {
        client_type::request request(url);
        request << boost::network::header("Connection", "close")
                << boost::network::header("Content-Type", "application/x-www-form-urlencoded")
                << boost::network::header("Content-Length", std::to_string(request_body.size()))
                << boost::network::header("User-Agent", "Is the order a clammbon?")
                << boost::network::body(request_body);

        client_type::response response = http_client_.post(request);
        std::string response_body = body(response);
        //std::cout << response_body << std::endl;
        return response_body;
    }

    client::client(
        std::string const& server_host,
        std::string const& problem_path,
        std::string const& submit_path
        ) : server_host_(server_host),
            problem_path_(problem_path),
            submit_path_(submit_path)
    {
    }

    std::future<std::string> client::get_problem(int const problem_id)
    {
        auto const url = (boost::format("http://%s%sprob%02d.ppm") % server_host_ % problem_path_ % problem_id).str();

        return std::async(
            std::launch::async,
            boost::bind(&client::http_request, this, url, "")
            );
    }

    std::future<std::string> client::submit(int const problem_id, std::string const& player_id, std::string const& answer)
    {
        std::unordered_map<std::string, std::string> content_list;
        content_list["playerid"] = player_id;
        content_list["problemid"] = (boost::format("%02d") % problem_id).str();
        content_list["answer"] = answer;

        auto const url  = (boost::format("http://%s%s") % server_host_ % submit_path_).str();
        auto const body = form_urlencode(content_list);

        return std::async(
            std::launch::async,
            boost::bind(&client::http_request, this, url, body)
            );
    }

    std::future<std::string> client::submit(int const problem_id, std::string const& player_id, answer_type const& answer)
    {
        return submit(problem_id, player_id, answer.serialize());
    }
} // namespace network

<commit_msg>自動連続ダウンロードの実装<commit_after>// MS WARNINGS MACRO
#define _SCL_SECURE_NO_WARNINGS

#include <future>
#include <memory>
#include <unordered_map>
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/network.hpp>
#include <boost/range/algorithm.hpp>
#include "network.hpp"

namespace network
{
    // RFC2396 の非予約文字のみエンコード．
    // .NET 4.0以前の EscapeDataString 相当のエンコードを行う．
    template<typename InputIterator, typename OutputIterator>
    OutputIterator client::urlencode(InputIterator first, InputIterator last, OutputIterator out) const
    {
        while(first != last)
        {
            if(
                (0x30<=*first && *first<=0x39) ||
                (0x41<=*first && *first<=0x5a) ||
                (0x61<=*first && *first<=0x7a) ||
                *first==0x21 ||
                *first==0x27 ||
                *first==0x28 ||
                *first==0x29 ||
                *first==0x2a ||
                *first==0x2d ||
                *first==0x2e ||
                *first==0x5f ||
                *first==0x7e
                )
            {
                *out++ = *first++;
            }
            else
            {
                std::string ss((boost::format("%%%02X") % (*first++ & 0xff)).str());
                out = std::copy(ss.begin(), ss.end(), out);
            }
        }
        return out;
    }

    std::string client::urlencode(std::string const& src) const
    {
        std::string ret;
        urlencode(src.cbegin(), src.cend(), std::back_inserter(ret));
        return ret;
    }

    std::string client::form_urlencode(std::unordered_map<std::string, std::string> const& header) const
    {
        std::string ret;

        for(auto const pair : header)
        {
            ret.append(urlencode(pair.first));
            ret.push_back('=');
            ret.append(urlencode(pair.second));
            ret.push_back('&');
        }
        ret.pop_back();

        return ret;
    }

    std::string client::http_request(std::string const url, std::string const request_body)
    {
        while(true)
        {
            client_type::request request(url);
            request << boost::network::header("Connection", "close")
                    << boost::network::header("Content-Type", "application/x-www-form-urlencoded")
                    << boost::network::header("Content-Length", std::to_string(request_body.size()))
                    << boost::network::header("User-Agent", "Is the order a clammbon?")
                    << boost::network::body(request_body);

            client_type::response response = http_client_.post(request);
            if(status(response) == 200)
            {
                std::string response_body = body(response);
                return response_body;
            }
        }
    }

    client::client(
        std::string const& server_host,
        std::string const& problem_path,
        std::string const& submit_path
        ) : server_host_(server_host),
            problem_path_(problem_path),
            submit_path_(submit_path)
    {
    }

    std::future<std::string> client::get_problem(int const problem_id)
    {
        auto const url = (boost::format("http://%s%sprob%02d.ppm") % server_host_ % problem_path_ % problem_id).str();

        return std::async(
            std::launch::async,
            boost::bind(&client::http_request, this, url, "")
            );
    }

    std::future<std::string> client::submit(int const problem_id, std::string const& player_id, std::string const& answer)
    {
        std::unordered_map<std::string, std::string> content_list;
        content_list["playerid"] = player_id;
        content_list["problemid"] = (boost::format("%02d") % problem_id).str();
        content_list["answer"] = answer;

        auto const url  = (boost::format("http://%s%s") % server_host_ % submit_path_).str();
        auto const body = form_urlencode(content_list);

        return std::async(
            std::launch::async,
            boost::bind(&client::http_request, this, url, body)
            );
    }

    std::future<std::string> client::submit(int const problem_id, std::string const& player_id, answer_type const& answer)
    {
        return submit(problem_id, player_id, answer.serialize());
    }
} // namespace network

<|endoftext|>


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

#include <ctime>
#include <string>
#include <sstream>
#include <iomanip>

namespace http {
namespace time {

//------------------------------------------------
// Get the current time in {Internet Standard Format}
//
// @return The current time as a std::string
//
// @note Returns an empty string if an error occurred
//------------------------------------------------
inline std::string now() {
  auto time_object = std::time(nullptr);
  auto tm          = std::gmtime(&time_object);

  if (tm) {
    std::ostringstream output;
    output << std::put_time(tm, "%a, %d %b %Y %H:%M:%S %Z");
    return output.str();
  }

  return std::string{};
}

} //< namespace time
} //< namespace http
<commit_msg>"Added timestamp function..."<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <ctime>
#include <string>
#include <sstream>
#include <iomanip>

namespace http {
namespace time {

//------------------------------------------------
// Get the time in {Internet Standard Format} from
// a {time_t} object
//
// @param time - The time_t object to get the time from
//
// @return The current time as a std::string
//
// @note Returns an empty string if an error occurred
//------------------------------------------------
inline std::string from_time_t(const time_t& time_) {
  auto tm = std::gmtime(&time_);

  if (tm) {
    std::ostringstream output;
    output << std::put_time(tm, "%a, %d %b %Y %H:%M:%S %Z");
    return output.str();
  }

  return std::string{};
}

//------------------------------------------------
// Get the current time in {Internet Standard Format}
//
// @return The current time as a std::string
//
// @note Returns an empty string if an error occurred
//------------------------------------------------
inline std::string now() {
  auto time_object = std::time(nullptr);
  return from_time_t(time_object);
}

} //< namespace time
} //< namespace http
<|endoftext|>