<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2014 Max-Planck-Institute for Intelligent Systems,
 *                     University of Southern California
 *    Jan Issac (jan.issac@gmail.com)
 *    Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 *
 *
 *  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.
 *
 */

/**
 * \date 10/21/2014
 * \author Jan Issac (jan.issac@gmail.com)
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * Max-Planck-Institute for Intelligent Systems,
 * University of Southern California
 */

#ifndef FL__FILTER__GAUSSIAN__POINT_SET_GAUSSIAN_HPP
#define FL__FILTER__GAUSSIAN__POINT_SET_GAUSSIAN_HPP

#include <map>

#include <Eigen/Dense>

#include <fast_filtering/distributions/gaussian.hpp>
#include <fast_filtering/filtering_library/exception/exception.hpp>
#include <fast_filtering/filtering_library/filter/filter_interface.hpp>

namespace fl
{

// Forward declaration
template <typename Point, int POINT_COUNT> class PointSetGaussian;

/**
 * Trait struct of a PointSetGaussian
 */
template <typename Point_, int POINT_COUNT>
struct Traits<PointSetGaussian<Point_, POINT_COUNT>>
{
    /**
     * @brief Gaussian sample type
     */
    typedef Point_ Point;

    /**
     * \brief Weight harbors the weights of a point. For each of the first two
     * moments there is a separate weight.
     *
     * Generally a single weight suffices. However, some transforms utilize
     * different weights for each moment to select a set of points representing
     * the underlying moments.
     */
    struct Weight
    {
        /**
         * First moment (mean) point weight
         */
        double w_mean;

        /**
         * Second centered moment (covariance) point weight
         */
        double w_cov;
    };

    /**
     * \typedef PointMatrix
     *
     * \brief Point container type
     *
     * \details
     * The point container type has a fixed-size dimension of a point
     * and the number of the points is statically known.
     */
    typedef Eigen::Matrix<
                typename Point::Scalar,
                Point::SizeAtCompileTime,
                POINT_COUNT
            > PointMatrix;

    /**
     * \typedef Weight
     *
     * Weight list of all points
     */
    typedef std::vector<Weight> WeightVector;

    /**
     * \typedef Base
     *
     * Base class type
     */
    typedef ff::Gaussian<Point> Base;
};

/**
 * \class PointSetGaussian
 *
 * PointSetGaussian is Gaussian distribution represented by a set of points
 * (a statistic)
 *
 * \tparam Point        Gaussian variable type
 * \tparam POINT_COUNT  Number of points representing the gaussian
 */
template <typename Point_, int POINT_COUNT = Eigen::Dynamic>
class PointSetGaussian:
        public ff::Gaussian<Point_>
{
public:
    typedef PointSetGaussian<Point_, POINT_COUNT> This;

    typedef typename Traits<This>::Base         Base;
    typedef typename Traits<This>::Point        Point;
    typedef typename Traits<This>::PointMatrix  PointMatrix;
    typedef typename Traits<This>::Weight       Weight;
    typedef typename Traits<This>::WeightVector WeightVector;

    using Base::Mean;
    using Base::Covariance;
    using Base::Precision;
    using Base::SquareRoot;
    using Base::DiagonalCovariance;
    using Base::DiagonalSquareRoot;
    using Base::DiagonalPrecision;
    using Base::SetStandard;
    using Base::Probability;
    using Base::LogProbability;
    using Base::Dimension;
    using Base::NoiseDimension;

public:
    /**
     * Creates a PointSetGaussian
     *
     * \param dimension     Sample space dimension
     * \param point_count   Number of points representing the Gaussian
     */
    PointSetGaussian(size_t point_count = POINT_COUNT > 0 ? POINT_COUNT : 0,
                     size_t dimension = Point::SizeAtCompileTime)
        : Base(dimension),
          points_(Dimension(), point_count),
          weights_(point_count)
    {
        points_.setZero();

        double weight = (point_count > 0) ? 1./double(point_count) : 0;
        std::fill(weights_.begin(), weights_.end(), Weight{weight, weight});
    }

    /**
     * \brief Overridable default constructor
     */
    virtual ~PointSetGaussian() { }

    /**
     * \return i-th point
     *
     * \param i Index of requested point
     *
     * \throw OutOfBoundsException
     */
    Point point(size_t i) const
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, points_.cols()));
        }

        return points_.col(i);
    }

    /**
     * \return weight of i-th point assuming both weights are the same
     *
     * \param i Index of requested point
     *
     * \throw OutOfBoundsException
     */
    double weight(size_t i)
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, weights_.size()));
        }

        return weights_[i].m_mean;
    }

    /**
     * \return weight of i-th point
     *
     * \param i Index of requested point
     *
     * \throw OutOfBoundsException
     */
    const Weight& weight(size_t i) const
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, points_.cols()));
        }

        return weights_[i];
    }

    /**
     * \return Point matrix
     */
    const PointMatrix& points() const noexcept
    {
        return points_;
    }

    /**
     * \return point weights vector
     */
    const WeightVector& weights() const noexcept
    {
        return weights_;
    }

    /**
     * Sets a given point at position i
     *
     * \param i         Index of point
     * \param p         The new point
     *
     * \throw OutOfBoundsException
     */
    void point(size_t i, Point p)
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, points_.cols()));
        }

        points_.col(i) = p;
    }

    /**
     * Sets a given point at position i along with its weights
     *
     * \param i         Index of point
     * \param p         The new point
     * \param w         Point weights. The weights determinaing the first two
     *                  moments are the same
     *
     * \throw OutOfBoundsException
     */
    void point(size_t i, Point p, double w)
    {
        point(i, p, Weight{w, w});
    }

    /**
     * Sets a given point at position i along with its weights
     *
     * \param i         Index of point
     * \param p         The new point
     * \param w_mean    point weight used to compute the first moment
     * \param w_cov     point weight used to compute the second centered moment
     *
     * \throw OutOfBoundsException
     */
    void point(size_t i, Point p, double w_mean , double w_cov)
    {
        point(i, p, Weight{w_mean, w_cov});
    }

    /**
     * Sets a given point at given position i along with its weights
     *
     * \param i         Index of point
     * \param p         The new point
     * \param weights   point weights
     *
     * \throw OutOfBoundsException
     */
    void point(size_t i, Point p, Weight weights)
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, points_.cols()));
        }

        points_.col(i) = p;
        weights_[i] = weights;
    }

    /**
     * Sets a given weight of a point at position i
     *
     * \param i         Index of point
     * \param w         Point weights. The weights determinaing the first two
     *                  moments are the same
     *
     * \throw OutOfBoundsException
     */
    void weight(size_t i, double w)
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, weights_.size()));
        }

        weights_[i] = Weight{w, w};
    }

    /**
     * Sets given weights of a point at position i
     *
     * \param i         Index of point
     * \param w_mean    point weight used to compute the first moment
     * \param w_cov     point weight used to compute the second centered moment
     *
     * \throw OutOfBoundsException
     */
    void weight(size_t i, Point p, double w_mean , double w_cov)
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, weights_.size()));
        }

        weights_[i] = Weight{w_mean, w_cov};
    }

    /**
     * Sets given weights of a point at position i
     *
     * \param i         Index of point
     * \param weights   point weights
     *
     * \throw OutOfBoundsException
     */
    void weight(size_t i, Weight weights)
    {
        if (is_out_of_bounds(i))
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, weights_.size()));
        }

        weights_[i] = weights;
    }

    /**
     * @return Centered points matrix.
     *
     * Creates a PointMatrix populated with zero mean points
     */
    PointMatrix centered_points() const noexcept
    {
        PointMatrix centered(points_.rows(), points_.cols);

        const size_t point_count = points_.cols();
        for (size_t i = 0; i < point_count; ++i)
        {
            centered.col(i) = points_.col(i) - Mean();
        }

        return centered;
    }

protected:
    /**
     * \return True of index i is out of bounds
     *
     * \param i Point index
     *
     * \internal asserts size equallity of points and weights
     */
    bool is_out_of_bounds(size_t i) const noexcept
    {
        assert(points_.cols() == weights_.size());

        return !(i < weights_.size());
    }

protected:
    /**
     * \brief point container
     */
    PointMatrix points_;

    /**
     * \brief weight container
     */
    WeightVector weights_;
};

}

#endif
<commit_msg>Extended point set gaussian<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2014 Max-Planck-Institute for Intelligent Systems,
 *                     University of Southern California
 *    Jan Issac (jan.issac@gmail.com)
 *    Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 *
 *
 *  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.
 *
 */

/**
 * \date 10/21/2014
 * \author Jan Issac (jan.issac@gmail.com)
 * Max-Planck-Institute for Intelligent Systems,
 * University of Southern California
 */

#ifndef FL__FILTER__GAUSSIAN__POINT_SET_GAUSSIAN_HPP
#define FL__FILTER__GAUSSIAN__POINT_SET_GAUSSIAN_HPP

#include <map>
#include <cmath>
#include <type_traits>

#include <Eigen/Dense>

#include <fast_filtering/distributions/gaussian.hpp>
#include <fast_filtering/filtering_library/exception/exception.hpp>
#include <fast_filtering/filtering_library/filter/filter_interface.hpp>

namespace fl
{

// Forward declaration
template <typename Point, int Points_> class PointSetGaussian;

/**
 * Trait struct of a PointSetGaussian
 */
template <typename Point_, int Points_>
struct Traits<PointSetGaussian<Point_, Points_>>
{
    /**
     * \brief Gaussian sample type
     */
    typedef Point_ Point;

    /**
     * \brief Base class type
     */
    typedef ff::Gaussian<Point> Base;

    /* Gaussian Base types */
    typedef typename ff::Traits<Base>::Vector   Vector;
    typedef typename ff::Traits<Base>::Scalar   Scalar;
    typedef typename ff::Traits<Base>::Noise    Noise;
    typedef typename ff::Traits<Base>::Operator Operator;

    /**
     * \brief Number of points for fixed-size set
     */
    enum
    {
        /**
         * \brief Gaussian dimension
         *
         * For fixed-size Point type and hence a fixed-size Gaussian, the
         * \c Dimension value is greater zero. Dynamic-size Gaussians have the
         * dymension Eigen::Dynamic.
         */
        Dimension = ff::Traits<Base>::Dimension,

        /**
         * \brief Number of points which provided by the PointSetGaussian.
         *
         * If the number of points is unknown and there for dynamic, then
         * NumberOfPoints is set to Eigen::Dynamic
         */
        NumberOfPoints = IsFixed<Points_>() ? Points_ : Eigen::Dynamic
    };

    /**
     * \brief Weight harbors the weights of a point. For each of the first two
     * moments there is a separate weight.
     *
     *
     * Generally a single weight suffices. However, some transforms utilize
     * different weights for each moment to select a set of points representing
     * the underlying moments.
     */
    struct Weight
    {
        /**
         * First moment (mean) point weight
         */
        double w_mean;

        /**
         * Second centered moment (covariance) point weight
         */
        double w_cov;
    };

    /**
     * \brief Point container type
     *
     * \details
     * The point container type has a fixed-size dimension of a point
     * and the number of the points is statically known.
     */
    typedef Eigen::Matrix<Scalar, Dimension, Points_ > PointMatrix;

    /**
     * @brief WeightVector
     */
    typedef Eigen::Matrix<
                typename Point::Scalar,
                Points_,
                1
            > WeightVector;

    /**
     * \brief Weight list of all points
     */
    typedef std::vector<Weight> Weights;

};

/**
 * \class PointSetGaussian
 *
 * PointSetGaussian is Gaussian distribution represented by a set of points
 * (a statistic)
 *
 * \tparam Point    Gaussian variable type
 * \tparam Points_  Number of points representing the gaussian
 */
template <typename Point_, int Points_ = Eigen::Dynamic>
class PointSetGaussian:
        public ff::Gaussian<Point_>
{
public:
    typedef PointSetGaussian<Point_, Points_> This;

    typedef typename Traits<This>::Base         Base;
    typedef typename Traits<This>::Scalar       Scalar;
    typedef typename Traits<This>::Operator     Operator;
    typedef typename Traits<This>::Noise        Noise;
    typedef typename Traits<This>::Point        Point;
    typedef typename Traits<This>::PointMatrix  PointMatrix;
    typedef typename Traits<This>::Weight       Weight;
    typedef typename Traits<This>::Weights      Weights;
    typedef typename Traits<This>::WeightVector WeightVector;

    using Base::Mean;
    using Base::Covariance;
    using Base::Precision;
    using Base::SquareRoot;
    using Base::DiagonalCovariance;
    using Base::DiagonalSquareRoot;
    using Base::DiagonalPrecision;
    using Base::SetStandard;
    using Base::Probability;
    using Base::LogProbability;
    using Base::Dimension;
    using Base::NoiseDimension;

public:
    /**
     * Creates a PointSetGaussian
     *
     * \param points_count   Number of points representing the Gaussian
     * \param dimension      Sample space dimension
     */
    PointSetGaussian(size_t points_count = (Points_ > 0) ? Points_ : 0,
                     size_t dimension = Point::RowsAtCompileTime)
        : Base(dimension),
          points_(Dimension(), points_count),
          weights_(points_count),
          changes_staged_(false)
    {
        assert(points_count >= 0);
        static_assert(Points_ >= Eigen::Dynamic, "Invalid point count");

        points_.setZero();

        double weight = (points_count > 0) ? 1./double(points_count) : 0;
        std::fill(weights_.begin(), weights_.end(), Weight{weight, weight});
    }

    /**
     * \brief Overridable default constructor
     */
    virtual ~PointSetGaussian() { }

    /**
     * Resizes a dynamic-size PointSetGaussian to a desired. For
     *
     * \param Points_   Number of points
     *
     * \throws ResizingFixedSizeEntityException
     */
    void resize(size_t points_count)
    {
        if (weights_.size() == points_count) return;

        if (IsFixed<Points_>())
        {
            BOOST_THROW_EXCEPTION(
                fl::ResizingFixedSizeEntityException(weights_.size(),
                                                     points_count,
                                                     "poit set Gaussian"));
        }

        points_.setZero(Dimension(), points_count);

        weights_.resize(points_count);
        const double weight = (points_count > 0)? 1. / double(points_count) : 0;
        std::fill(weights_.begin(), weights_.end(), Weight{weight, weight});
    }

    /**
     * Sets the new Gaussian dimension for dynamic-size Gaussian (not to confuse
     * with the number of points)
     *
     * @param new_dimension New Gaussian dimension
     */
    virtual void Dimension(size_t new_dimension)
    {
        Base::Dimension(new_dimension);
        points_.resize(Dimension(), count_points());
    }

    /**
     * @return The number of points
     */
    size_t count_points() const
    {
        return points_.cols();
    }

    /**
     * \return i-th point
     *
     * \param i Index of requested point
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    Point point(size_t i) const
    {
        assert_bounds(i);

        return points_.col(i);
    }

    /**
     * \return weight of i-th point assuming both weights are the same
     *
     * \param i Index of requested point
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    double weight(size_t i)
    {
        assert_bounds(i);

        return weights_[i].w_mean;
    }

    /**
     * \return weights of i-th point
     *
     * \param i Index of requested point
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    const Weight& weights(size_t i) const
    {
        assert_bounds(i);

        return weights_[i];
    }

    /**
     * \return Point matrix
     */
    const PointMatrix& points() const noexcept
    {
        return points_;
    }

    /**
     * \return point weights vector
     */
    const Weights& weights() const noexcept
    {
        return weights_;
    }

    /**
     * @return Returns the weights for the mean of the points as a vector
     */
    WeightVector mean_weights_vector() const noexcept
    {
        const size_t point_count = count_points();

        WeightVector weight_vec(point_count);

        for (size_t i = 0; i < point_count; ++i)
        {
            weight_vec(i) = weights_[i].w_mean;
        }

        return weight_vec;
    }

    /**
     * @return Returns the weights for the covariance of the points as a vector
     */
    WeightVector covariance_weights_vector() const noexcept
    {
        const size_t point_count = count_points();

        WeightVector weight_vec(point_count);

        for (size_t i = 0; i < point_count; ++i)
        {
            weight_vec(i) = weights_[i].w_cov;
        }

        return weight_vec;
    }

    /**
     * Sets a given point at position i
     *
     * \param i         Index of point
     * \param p         The new point
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void point(size_t i, Point p)
    {
        assert_bounds(i);

        points_.col(i) = p;
        stage_point_changes();
    }

    /**
     * Sets a given point at position i along with its weights
     *
     * \param i         Index of point
     * \param p         The new point
     * \param w         Point weights. The weights determinaing the first two
     *                  moments are the same
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void point(size_t i, Point p, double w)
    {
        point(i, p, Weight{w, w});
    }

    /**
     * Sets a given point at position i along with its weights
     *
     * \param i         Index of point
     * \param p         The new point
     * \param w_mean    point weight used to compute the first moment
     * \param w_cov     point weight used to compute the second centered moment
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void point(size_t i, Point p, double w_mean , double w_cov)
    {
        point(i, p, Weight{w_mean, w_cov});
    }

    /**
     * Sets a given point at given position i along with its weights
     *
     * \param i         Index of point
     * \param p         The new point
     * \param weights   point weights
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void point(size_t i, Point p, Weight weights)
    {
        assert_bounds(i);

        points_.col(i) = p;
        weights_[i] = weights;
        stage_point_changes();
    }

    /**
     * Sets a given weight of a point at position i
     *
     * \param i         Index of point
     * \param w         Point weights. The weights determinaing the first two
     *                  moments are the same
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void weight(size_t i, double w)
    {
        weight(i, Weight{w, w});
    }

    /**
     * Sets given weights of a point at position i
     *
     * \param i         Index of point
     * \param w_mean    point weight used to compute the first moment
     * \param w_cov     point weight used to compute the second centered moment
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void weight(size_t i, double w_mean , double w_cov)
    {
        weight(i, Weight{w_mean, w_cov});
    }

    /**
     * Sets given weights of a point at position i
     *
     * \param i         Index of point
     * \param weights   point weights
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void weight(size_t i, Weight weights)
    {
        assert_bounds(i);

        weights_[i] = weights;
        stage_point_changes();
    }

    void commit_point_changes()
    {
        changes_staged_ = false;

        if (moments_dirty_)
        {
            PointMatrix P = weighted_centered_points();
            Covariance(P * P.transpose());
            Mean(weighted_mean());

            moments_dirty_ = false;
        }
    }

    /**
     * @return Centered points matrix.
     *
     * Creates a PointMatrix populated with zero mean points
     */
    PointMatrix centered_points() const noexcept
    {
        PointMatrix centered(points_.rows(), points_.cols());

        const Point weighted_mean = weighted_mean();
        const size_t point_count = points_.cols();
        for (size_t i = 0; i < point_count; ++i)
        {
            centered.col(i) = points_.col(i) - weighted_mean;
        }

        return centered;
    }

    /**
     * @return Weighted centered points matrix.
     *
     * Creates a PointMatrix populated with weighted zero mean points
     */
    PointMatrix weighted_centered_points() const noexcept
    {
        PointMatrix centered(points_.rows(), points_.cols());

        const Point mean = weighted_mean();
        const size_t point_count = points_.cols();
        for (size_t i = 0; i < point_count; ++i)
        {
            centered.col(i) =
                    weights_[i].w_cov * (points_.col(i) - mean);
        }

        return centered;
    }

    /**
     * @return The weighted mean of all points
     */
    Point weighted_mean() const
    {
        Point weighted_mean;
        weighted_mean.setZero(Dimension());

        const size_t point_count = points_.cols();
        for (size_t i = 0; i < point_count; ++i)
        {
            weighted_mean += weights_[i].w_mean * points_.col(i);
        }

        return weighted_mean;
    }

    /**
     * The point set becomes dirty once one of moment representations has been
     * changed.
     *
     * @return point set dirty status
     */
    bool is_point_set_dirty() const noexcept
    {
        return point_set_dirty_;
    }

    /* Gaussian interface */

    virtual Vector Mean() const
    {
        if (moments_dirty_)
        {

        }

        return mean_;
    }

    virtual void Mean(const Vector& mean) noexcept
    {
        point_set_dirty_ = true;
        Base::Mean(mean);
    }

    virtual void Covariance(const Operator& covariance) noexcept
    {
        point_set_dirty_ = true;
        Covariance(covariance);
    }

    virtual void SquareRoot(const Operator& square_root) noexcept
    {
        point_set_dirty_ = true;
        SquareRoot(square_root);
    }

    virtual void Precision(const Operator& precision) noexcept
    {
        point_set_dirty_ = true;
        Precision(precision);
    }

    virtual void DiagonalCovariance(const Operator& diag_covariance) noexcept
    {
        point_set_dirty_ = true;
        DiagonalCovariance(diag_covariance);
    }

    virtual void DiagonalSquareRoot(const Operator& diag_square_root) noexcept
    {
        point_set_dirty_ = true;
        DiagonalSquareRoot(diag_square_root);
    }

    virtual void DiagonalPrecision(const Operator& diag_precision) noexcept
    {
        point_set_dirty_ = true;
        DiagonalPrecision(diag_precision);
    }

protected:
    /**
     * Asserts that the specified index is within bounds and that the dimension
     * is greater zero.
     *
     * \param i Point index
     *
     * \internal asserts size equallity of points and weights
     *
     * \throws OutOfBoundsException
     * \throws ZeroDimensionException
     */
    void assert_bounds(size_t i) const
    {
        assert(points_.cols() == weights_.size());

        if (i >= weights_.size())
        {
            BOOST_THROW_EXCEPTION(OutOfBoundsException(i, weights_.size()));
        }

        if (Dimension() == 0)
        {
            BOOST_THROW_EXCEPTION(ZeroDimensionException("PointSetGaussian"));
        }
    }

    void stage_point_changes()
    {
        moments_dirty_ = true;
        changes_staged_ = true;
    }

protected:
    /**
     * \brief point container
     */
    mutable PointMatrix points_;

    /**
     * \brief weight container
     */
    mutable Weights weights_;

    bool changes_staged_;
    bool moments_dirty_;
    bool point_set_dirty_;
};

}

#endif
<|endoftext|>


<commit_before>/*      $Id$                 */

#include <base/exceptions.h>
#include <string>
#include <strstream>

ExceptionBase::ExceptionBase () :
		file(""), line(0), function(""), cond(""), exc("")
{};

ExceptionBase::ExceptionBase (const char* f, const int l, const char *func,
			      const char* c, const char *e) :
		file(f), line(l), function(func), cond(c), exc(e)
{};

void ExceptionBase::SetFields (const char* f,
			       const int l,
			       const char *func,
			       const char *c,
			       const char *e) {
  file = f;
  line = l;
  function = func;
  cond = c;
  exc  = e;
};

void ExceptionBase::PrintExcData (ostream &out) const {
  out << "An error occurred in line <" << line
      << "> of file <" << file
      << "> in function" << endl
      << "    " << function << endl
      << "The violated condition was: "<< endl
      << "    " << cond << endl
      << "The name and call sequence of the exception was:" << endl
      << "    " << exc  << endl
      << "Additional Information: " << endl;
};

void ExceptionBase::PrintInfo (ostream &out) const {
  out << "(none)" << endl;
};

const char * ExceptionBase::what () const {
				   // have a place where to store the
				   // description of the exception as a char *
				   //
				   // this thing obviously is not multi-threading
				   // safe, but we don't care about that for now
				   //
				   // we need to make this object static, since
				   // we want to return the data stored in it
				   // and therefore need a liftime which is
				   // longer than the execution time of this
				   // function
  static string description;
				   // convert the messages printed by the
				   // exceptions into a string
  ostrstream converter;

  converter << "--------------------------------------------------------"
	    << endl;
				   // put general info into the string
  PrintExcData (converter);
				   // put in exception specific data
  PrintInfo (converter);

  converter << "--------------------------------------------------------"
	    << endl;

  description = converter.str();

  return description.c_str();
};

<commit_msg>Fix a point I was not really aware about previously: strstreams need <<ends!.<commit_after>/*      $Id$                 */

#include <base/exceptions.h>
#include <string>
#include <strstream>

ExceptionBase::ExceptionBase () :
		file(""), line(0), function(""), cond(""), exc("")
{};

ExceptionBase::ExceptionBase (const char* f, const int l, const char *func,
			      const char* c, const char *e) :
		file(f), line(l), function(func), cond(c), exc(e)
{};

void ExceptionBase::SetFields (const char* f,
			       const int l,
			       const char *func,
			       const char *c,
			       const char *e) {
  file = f;
  line = l;
  function = func;
  cond = c;
  exc  = e;
};

void ExceptionBase::PrintExcData (ostream &out) const {
  out << "An error occurred in line <" << line
      << "> of file <" << file
      << "> in function" << endl
      << "    " << function << endl
      << "The violated condition was: "<< endl
      << "    " << cond << endl
      << "The name and call sequence of the exception was:" << endl
      << "    " << exc  << endl
      << "Additional Information: " << endl;
};

void ExceptionBase::PrintInfo (ostream &out) const {
  out << "(none)" << endl;
};

const char * ExceptionBase::what () const {
				   // have a place where to store the
				   // description of the exception as a char *
				   //
				   // this thing obviously is not multi-threading
				   // safe, but we don't care about that for now
				   //
				   // we need to make this object static, since
				   // we want to return the data stored in it
				   // and therefore need a liftime which is
				   // longer than the execution time of this
				   // function
  static string description;
				   // convert the messages printed by the
				   // exceptions into a string
  ostrstream converter;

  converter << "--------------------------------------------------------"
	    << endl;
				   // put general info into the string
  PrintExcData (converter);
				   // put in exception specific data
  PrintInfo (converter);

  converter << "--------------------------------------------------------"
	    << endl
	    << ends;

  description = converter.str();

  return description.c_str();
};

<|endoftext|>


<commit_before>// Copyright Contributors to the OpenVDB Project
// SPDX-License-Identifier: MPL-2.0
//
/// @file SOP_OpenVDB_LOD.cc
///
/// @author FX R&D OpenVDB team
///
/// @brief Generate one or more levels of a volume mipmap.

#include <houdini_utils/ParmFactory.h>
#include <openvdb_houdini/SOP_NodeVDB.h>
#include <openvdb_houdini/Utils.h>
#include <openvdb/tools/MultiResGrid.h>

#include <hboost/algorithm/string/join.hpp>

#include <string>
#include <vector>

namespace hvdb = openvdb_houdini;
namespace hutil = houdini_utils;

class SOP_OpenVDB_LOD: public hvdb::SOP_NodeVDB
{
public:
    SOP_OpenVDB_LOD(OP_Network*, const char* name, OP_Operator*);
    ~SOP_OpenVDB_LOD() override {}

    static OP_Node* factory(OP_Network*, const char* name, OP_Operator*);

    int isRefInput(unsigned input) const override { return (input > 0); }

    class Cache: public SOP_VDBCacheOptions { OP_ERROR cookVDBSop(OP_Context&) override; };

protected:
    bool updateParmsFlags() override;
};

////////////////////////////////////////

void
newSopOperator(OP_OperatorTable* table)
{
    if (table == nullptr) return;

    hutil::ParmList parms;

    parms.add(hutil::ParmFactory(PRM_STRING, "group", "Group")
        .setChoiceList(&hutil::PrimGroupMenuInput1)
        .setTooltip("Specify a subset of the input VDB grids to be processed.")
        .setDocumentation(
            "A subset of the input VDB grids to be processed"
            " (see [specifying volumes|/model/volumes#group])"));

    parms.add(hutil::ParmFactory(PRM_ORD, "lod", "LOD Mode")
        .setDefault(PRMzeroDefaults)
        .setChoiceListItems(PRM_CHOICELIST_SINGLE, {
            "single", "Single Level",
            "range",  "Level Range",
            "mipmaps","LOD Pyramid"
        })
        .setDocumentation(
            "How to build the LOD pyramid\n\n"
            "Single Level:\n"
            "    Build a single, filtered VDB.\n\n"
            "Level Range:\n"
            "    Build a series of VDBs of progressively lower resolution\n"
            "    within a given range of scales.\n\n"
            "LOD Pyramid:\n"
            "    Build a standard pyramid of VDBs of decreasing resolution.\n"
            "    Each level of the pyramid is half the resolution in each\n"
            "    dimension of the previous level, starting with the input VDB.\n"));

    parms.add(hutil::ParmFactory(PRM_FLT_J, "level", "Level")
        .setDefault(PRMoneDefaults)
        .setRange(PRM_RANGE_RESTRICTED, 0.0, PRM_RANGE_UI, 10.0)
        .setTooltip("Specify which single level to produce.\n"
            "Level 0, the highest-resolution level, is the input VDB."));

    {
        const std::vector<fpreal> defaultRange{
            fpreal(0.0), // start
            fpreal(2.0), // end
            fpreal(1.0)  // step
        };

        parms.add(hutil::ParmFactory(PRM_FLT_J, "range", "Range")
            .setDefault(defaultRange)
            .setVectorSize(3)
            .setRange(PRM_RANGE_RESTRICTED, 0.0, PRM_RANGE_UI, 10.0)
            .setTooltip(
                "In Level Range mode, specify the (inclusive) starting and ending levels"
                " and the level step. Level 0, the highest-resolution level, is the input VDB;"
                " fractional levels are allowed."));
    }

    parms.add(hutil::ParmFactory(PRM_INT_J, "count", "Count")
        .setDefault(PRMtwoDefaults)
        .setRange(PRM_RANGE_RESTRICTED, 2, PRM_RANGE_UI, 10)
        .setTooltip(
            "In LOD Pyramid mode, specify the number of pyramid levels to generate."
            " Each level is half the resolution of the previous level."));

    parms.add(hutil::ParmFactory(PRM_TOGGLE, "reuse", "Preserve Grid Names")
        .setDefault(PRMzeroDefaults)
        .setTooltip(
            "In Single Level mode, give the output VDB the same name as the input VDB."));

    hvdb::OpenVDBOpFactory("VDB LOD", SOP_OpenVDB_LOD::factory, parms, *table)
        .addInput("VDBs")
        .setVerb(SOP_NodeVerb::COOK_INPLACE, []() { return new SOP_OpenVDB_LOD::Cache; })
        .setDocumentation("\
#icon: COMMON/openvdb\n\
#tags: vdb\n\
\n\
\"\"\"Build an LOD pyramid from a VDB volume.\"\"\"\n\
\n\
@overview\n\
\n\
This node creates filtered versions of a VDB volume at multiple resolutions,\n\
providing mipmap-like levels of detail.\n\
The low-resolution versions can be used both as thumbnails for fast processing\n\
and for constant-time, filtered lookups over large areas of a volume.\n\
\n\
@related\n\
- [OpenVDB Resample|Node:sop/DW_OpenVDBResample]\n\
\n\
@examples\n\
\n\
See [openvdb.org|http://www.openvdb.org/download/] for source code\n\
and usage examples.\n");
}

bool
SOP_OpenVDB_LOD::updateParmsFlags()
{
    bool changed = false;

    const auto lodMode = evalInt("lod", 0, 0);

    changed |= enableParm("level", lodMode == 0);
    changed |= enableParm("reuse", lodMode == 0);
    changed |= enableParm("range", lodMode == 1);
    changed |= enableParm("count", lodMode == 2);

    return changed;
}

////////////////////////////////////////

OP_Node*
SOP_OpenVDB_LOD::factory(OP_Network* net,
    const char* name, OP_Operator* op)
{
    return new SOP_OpenVDB_LOD(net, name, op);
}

SOP_OpenVDB_LOD::SOP_OpenVDB_LOD(OP_Network* net,
    const char* name, OP_Operator* op):
    hvdb::SOP_NodeVDB(net, name, op)
{
}

////////////////////////////////////////

namespace {

template<openvdb::Index Order>
struct MultiResGridFractionalOp
{
    MultiResGridFractionalOp(float f) : level(f) {}
    template<typename GridType>
    void operator()(const GridType& grid)
    {
        if ( level <= 0.0f ) {
            outputGrid = typename GridType::Ptr( new GridType(grid) );
        } else {
            const size_t levels = openvdb::math::Ceil(level) + 1;
            using TreeT = typename GridType::TreeType;
            openvdb::tools::MultiResGrid<TreeT> mrg( levels, grid );
            outputGrid = mrg.template createGrid<Order>( level );
        }
    }
    const float level;
    hvdb::GridPtr outputGrid;
};

template<openvdb::Index Order>
struct MultiResGridRangeOp
{
    MultiResGridRangeOp(float start_, float end_, float step_, hvdb::Interrupter& boss_)
        : start(start_), end(end_), step(step_), outputGrids(), boss(&boss_)
    {}

    template<typename GridType>
    void operator()(const GridType& grid)
    {
        if ( end > 0.0f ) {
            const size_t levels = openvdb::math::Ceil(end) + 1;
            using TreeT = typename GridType::TreeType;
            openvdb::tools::MultiResGrid<TreeT> mrg( levels, grid );

            // inclusive range
            for (float level = start; !(level > end); level += step) {

                if (boss->wasInterrupted()) break;

                outputGrids.push_back( mrg.template createGrid<Order>( level ) );
            }
        }
    }
    const float start, end, step;
    std::vector<hvdb::GridPtr> outputGrids;
    hvdb::Interrupter * const boss;
};

struct MultiResGridIntegerOp
{
    MultiResGridIntegerOp(size_t n) : levels(n) {}
    template<typename GridType>
    void operator()(const GridType& grid)
    {
        using TreeT = typename GridType::TreeType;
        openvdb::tools::MultiResGrid<TreeT> mrg( levels, grid );
        outputGrids = mrg.grids();
    }
    const size_t levels;
    openvdb::GridPtrVecPtr outputGrids;
};

inline bool
isValidRange(float start, float end, float step)
{
    if (start < 0.0f || !(step > 0.0f) || end < 0.0f) {
        return false;
    }

    return !(start > end);
}

}//unnamed namespace

////////////////////////////////////////

OP_ERROR
SOP_OpenVDB_LOD::Cache::cookVDBSop(OP_Context& context)
{
    try {
        const fpreal time = context.getTime();

        // Get the group of grids to process.
        const GA_PrimitiveGroup* group = matchGroup(*gdp, evalStdString("group", time));

        std::vector<std::string> skipped;

        hvdb::Interrupter boss("Creating VDB LoD pyramid");
        GA_RWHandleS name_h(gdp, GA_ATTRIB_PRIMITIVE, "name");

        const auto lodMode = evalInt("lod", 0, 0);
        if (lodMode == 0) {

            const bool reuseName = evalInt("reuse", 0, 0) > 0;
            MultiResGridFractionalOp<1> op( float(evalFloat("level", 0, time)) );
            for (hvdb::VdbPrimIterator it(gdp, group); it; ++it) {

                if (boss.wasInterrupted()) return error();

                if (name_h.isValid())
                    it->getGrid().setName(static_cast<const char *>(name_h.get(it->getMapOffset())));

                if (!it->getGrid().transform().isLinear()) {
                    skipped.push_back(it->getGrid().getName());
                    continue;
                }

                hvdb::GEOvdbApply<hvdb::VolumeGridTypes>(**it, op);

                if (boss.wasInterrupted()) return error();

                if (reuseName) op.outputGrid->setName( it->getGrid().getName() );

                hvdb::createVdbPrimitive(*gdp, op.outputGrid);

                gdp->destroyPrimitiveOffset(it->getMapOffset(), /*and_points=*/true);
            }

        } else if (lodMode == 1) {

            const float start = float(evalFloat("range", 0, time));
            const float end = float(evalFloat("range", 1, time));
            const float step = float(evalFloat("range", 2, time));

            if (!isValidRange(start, end, step)) {
                addError(SOP_MESSAGE, "Invalid range, make sure that "
                    "start <= end and the step size is a positive number.");
                return error();
            }

            MultiResGridRangeOp<1> op( start, end, step, boss );
            for (hvdb::VdbPrimIterator it(gdp, group); it; ++it) {

                if (boss.wasInterrupted()) return error();

                if (name_h.isValid())
                    it->getGrid().setName(static_cast<const char *>(name_h.get(it->getMapOffset())));

                if (!it->getGrid().transform().isLinear()) {
                    skipped.push_back(it->getGrid().getName());
                    continue;
                }

                hvdb::GEOvdbApply<hvdb::VolumeGridTypes>(**it, op);

                if (boss.wasInterrupted()) return error();

                for (size_t i=0; i< op.outputGrids.size(); ++i) {
                    hvdb::createVdbPrimitive(*gdp, op.outputGrids[i]);
                }

                gdp->destroyPrimitiveOffset(it->getMapOffset(), /*and_points=*/true);
            }
        } else if (lodMode == 2) {

            MultiResGridIntegerOp op( evalInt("count", 0, time) );
            for (hvdb::VdbPrimIterator it(gdp, group); it; ++it) {

                if (boss.wasInterrupted()) return error();

                if (name_h.isValid())
                    it->getGrid().setName(static_cast<const char *>(name_h.get(it->getMapOffset())));

                if (!it->getGrid().transform().isLinear()) {
                    skipped.push_back(it->getGrid().getName());
                    continue;
                }

                hvdb::GEOvdbApply<hvdb::VolumeGridTypes>(**it, op);

                if (boss.wasInterrupted()) return error();

                for (size_t i=0; i< op.outputGrids->size(); ++i) {
                    hvdb::createVdbPrimitive(*gdp, op.outputGrids->at(i));
                }

                gdp->destroyPrimitiveOffset(it->getMapOffset(), /*and_points=*/true);
            }

        } else {
            addError(SOP_MESSAGE, "Invalid LOD option.");
        }

        if (!skipped.empty()) {
            addWarning(SOP_MESSAGE, ("Unable to process grid(s): " +
                hboost::algorithm::join(skipped, ", ")).c_str());
        }

    } catch (std::exception& e) {
        addError(SOP_MESSAGE, e.what());
    }

    return error();
}
<commit_msg>Drop incompatible MultiResGrid data<commit_after>// Copyright Contributors to the OpenVDB Project
// SPDX-License-Identifier: MPL-2.0
//
/// @file SOP_OpenVDB_LOD.cc
///
/// @author FX R&D OpenVDB team
///
/// @brief Generate one or more levels of a volume mipmap.

#include <houdini_utils/ParmFactory.h>
#include <openvdb_houdini/SOP_NodeVDB.h>
#include <openvdb_houdini/Utils.h>
#include <openvdb/tools/MultiResGrid.h>

#include <hboost/algorithm/string/join.hpp>

#include <string>
#include <vector>

namespace hvdb = openvdb_houdini;
namespace hutil = houdini_utils;

class SOP_OpenVDB_LOD: public hvdb::SOP_NodeVDB
{
public:
    SOP_OpenVDB_LOD(OP_Network*, const char* name, OP_Operator*);
    ~SOP_OpenVDB_LOD() override {}

    static OP_Node* factory(OP_Network*, const char* name, OP_Operator*);

    int isRefInput(unsigned input) const override { return (input > 0); }

    class Cache: public SOP_VDBCacheOptions { OP_ERROR cookVDBSop(OP_Context&) override; };

protected:
    bool updateParmsFlags() override;
};

////////////////////////////////////////

void
newSopOperator(OP_OperatorTable* table)
{
    if (table == nullptr) return;

    hutil::ParmList parms;

    parms.add(hutil::ParmFactory(PRM_STRING, "group", "Group")
        .setChoiceList(&hutil::PrimGroupMenuInput1)
        .setTooltip("Specify a subset of the input VDB grids to be processed.")
        .setDocumentation(
            "A subset of the input VDB grids to be processed"
            " (see [specifying volumes|/model/volumes#group])"));

    parms.add(hutil::ParmFactory(PRM_ORD, "lod", "LOD Mode")
        .setDefault(PRMzeroDefaults)
        .setChoiceListItems(PRM_CHOICELIST_SINGLE, {
            "single", "Single Level",
            "range",  "Level Range",
            "mipmaps","LOD Pyramid"
        })
        .setDocumentation(
            "How to build the LOD pyramid\n\n"
            "Single Level:\n"
            "    Build a single, filtered VDB.\n\n"
            "Level Range:\n"
            "    Build a series of VDBs of progressively lower resolution\n"
            "    within a given range of scales.\n\n"
            "LOD Pyramid:\n"
            "    Build a standard pyramid of VDBs of decreasing resolution.\n"
            "    Each level of the pyramid is half the resolution in each\n"
            "    dimension of the previous level, starting with the input VDB.\n"));

    parms.add(hutil::ParmFactory(PRM_FLT_J, "level", "Level")
        .setDefault(PRMoneDefaults)
        .setRange(PRM_RANGE_RESTRICTED, 0.0, PRM_RANGE_UI, 10.0)
        .setTooltip("Specify which single level to produce.\n"
            "Level 0, the highest-resolution level, is the input VDB."));

    {
        const std::vector<fpreal> defaultRange{
            fpreal(0.0), // start
            fpreal(2.0), // end
            fpreal(1.0)  // step
        };

        parms.add(hutil::ParmFactory(PRM_FLT_J, "range", "Range")
            .setDefault(defaultRange)
            .setVectorSize(3)
            .setRange(PRM_RANGE_RESTRICTED, 0.0, PRM_RANGE_UI, 10.0)
            .setTooltip(
                "In Level Range mode, specify the (inclusive) starting and ending levels"
                " and the level step. Level 0, the highest-resolution level, is the input VDB;"
                " fractional levels are allowed."));
    }

    parms.add(hutil::ParmFactory(PRM_INT_J, "count", "Count")
        .setDefault(PRMtwoDefaults)
        .setRange(PRM_RANGE_RESTRICTED, 2, PRM_RANGE_UI, 10)
        .setTooltip(
            "In LOD Pyramid mode, specify the number of pyramid levels to generate."
            " Each level is half the resolution of the previous level."));

    parms.add(hutil::ParmFactory(PRM_TOGGLE, "reuse", "Preserve Grid Names")
        .setDefault(PRMzeroDefaults)
        .setTooltip(
            "In Single Level mode, give the output VDB the same name as the input VDB."));

    hvdb::OpenVDBOpFactory("VDB LOD", SOP_OpenVDB_LOD::factory, parms, *table)
        .addInput("VDBs")
        .setVerb(SOP_NodeVerb::COOK_INPLACE, []() { return new SOP_OpenVDB_LOD::Cache; })
        .setDocumentation("\
#icon: COMMON/openvdb\n\
#tags: vdb\n\
\n\
\"\"\"Build an LOD pyramid from a VDB volume.\"\"\"\n\
\n\
@overview\n\
\n\
This node creates filtered versions of a VDB volume at multiple resolutions,\n\
providing mipmap-like levels of detail.\n\
The low-resolution versions can be used both as thumbnails for fast processing\n\
and for constant-time, filtered lookups over large areas of a volume.\n\
\n\
@related\n\
- [OpenVDB Resample|Node:sop/DW_OpenVDBResample]\n\
\n\
@examples\n\
\n\
See [openvdb.org|http://www.openvdb.org/download/] for source code\n\
and usage examples.\n");
}

bool
SOP_OpenVDB_LOD::updateParmsFlags()
{
    bool changed = false;

    const auto lodMode = evalInt("lod", 0, 0);

    changed |= enableParm("level", lodMode == 0);
    changed |= enableParm("reuse", lodMode == 0);
    changed |= enableParm("range", lodMode == 1);
    changed |= enableParm("count", lodMode == 2);

    return changed;
}

////////////////////////////////////////

OP_Node*
SOP_OpenVDB_LOD::factory(OP_Network* net,
    const char* name, OP_Operator* op)
{
    return new SOP_OpenVDB_LOD(net, name, op);
}

SOP_OpenVDB_LOD::SOP_OpenVDB_LOD(OP_Network* net,
    const char* name, OP_Operator* op):
    hvdb::SOP_NodeVDB(net, name, op)
{
}

////////////////////////////////////////

namespace {

template<openvdb::Index Order>
struct MultiResGridFractionalOp
{
    MultiResGridFractionalOp(float f) : level(f) {}
    template<typename GridType>
    void operator()(const GridType& grid)
    {
        using TreeT = typename GridType::TreeType;
        if ( level <= 0.0f ) {
            outputGrid = typename GridType::Ptr( new GridType(grid) );
        } else {
            const size_t levels = openvdb::math::Ceil(level) + 1;
            const GridType* gridPtr = &grid;
#if OPENVDB_ABI_VERSION_NUMBER >= 7 // Grid::copyReplacingMetadata() only available in ABI>=7
            // if grid already has MultiResGrid_Level metadata with type int64, remove it
            typename GridType::ConstPtr newGridPtr;
            auto meta = grid.template getMetadata<openvdb::Int64Metadata>("MultiResGrid_Level");
            if (meta) {
                // deep copy meta map and remove element
                openvdb::MetaMap metaMap(static_cast<const openvdb::MetaMap&>(grid));
                metaMap.removeMeta("MultiResGrid_Level");
                // the tree and transform are shared with the input grid, but meta map is different
                newGridPtr = grid.copyReplacingMetadata(metaMap);
                gridPtr = newGridPtr.get();
            }
#endif
            openvdb::tools::MultiResGrid<TreeT> mrg( levels, *gridPtr );
            outputGrid = mrg.template createGrid<Order>( level );
        }
    }
    const float level;
    hvdb::GridPtr outputGrid;
};

template<openvdb::Index Order>
struct MultiResGridRangeOp
{
    MultiResGridRangeOp(float start_, float end_, float step_, hvdb::Interrupter& boss_)
        : start(start_), end(end_), step(step_), outputGrids(), boss(&boss_)
    {}

    template<typename GridType>
    void operator()(const GridType& grid)
    {
        using TreeT = typename GridType::TreeType;
        if ( end > 0.0f ) {
            const size_t levels = openvdb::math::Ceil(end) + 1;
            const GridType* gridPtr = &grid;
#if OPENVDB_ABI_VERSION_NUMBER >= 7 // Grid::copyReplacingMetadata() only available in ABI>=7
            // if grid already has MultiResGrid_Level metadata with type int64, remove it
            typename GridType::ConstPtr newGridPtr;
            auto meta = grid.template getMetadata<openvdb::Int64Metadata>("MultiResGrid_Level");
            if (meta) {
                // deep copy meta map and remove element
                openvdb::MetaMap metaMap(static_cast<const openvdb::MetaMap&>(grid));
                metaMap.removeMeta("MultiResGrid_Level");
                // the tree and transform are shared with the input grid, but meta map is different
                newGridPtr = grid.copyReplacingMetadata(metaMap);
                gridPtr = newGridPtr.get();
            }
#endif
            openvdb::tools::MultiResGrid<TreeT> mrg( levels, *gridPtr );

            // inclusive range
            for (float level = start; !(level > end); level += step) {

                if (boss->wasInterrupted()) break;

                outputGrids.push_back( mrg.template createGrid<Order>( level ) );
            }
        }
    }
    const float start, end, step;
    std::vector<hvdb::GridPtr> outputGrids;
    hvdb::Interrupter * const boss;
};

struct MultiResGridIntegerOp
{
    MultiResGridIntegerOp(size_t n) : levels(n) {}
    template<typename GridType>
    void operator()(const GridType& grid)
    {
        using TreeT = typename GridType::TreeType;
        const GridType* gridPtr = &grid;
#if OPENVDB_ABI_VERSION_NUMBER >= 7 // Grid::copyReplacingMetadata() only available in ABI>=7
        // if grid already has MultiResGrid_Level metadata with type float, remove it
        typename GridType::ConstPtr newGridPtr;
        auto meta = grid.template getMetadata<openvdb::FloatMetadata>("MultiResGrid_Level");
        if (meta) {
            // deep copy meta map and remove element
            openvdb::MetaMap metaMap(static_cast<const openvdb::MetaMap&>(grid));
            metaMap.removeMeta("MultiResGrid_Level");
            // the tree and transform are shared with the input grid, but meta map is different
            newGridPtr = grid.copyReplacingMetadata(metaMap);
            gridPtr = newGridPtr.get();
        }
#endif
        openvdb::tools::MultiResGrid<TreeT> mrg( levels, *gridPtr );
        outputGrids = mrg.grids();
    }
    const size_t levels;
    openvdb::GridPtrVecPtr outputGrids;
};

inline bool
isValidRange(float start, float end, float step)
{
    if (start < 0.0f || !(step > 0.0f) || end < 0.0f) {
        return false;
    }

    return !(start > end);
}

}//unnamed namespace

////////////////////////////////////////

OP_ERROR
SOP_OpenVDB_LOD::Cache::cookVDBSop(OP_Context& context)
{
    try {
        const fpreal time = context.getTime();

        // Get the group of grids to process.
        const GA_PrimitiveGroup* group = matchGroup(*gdp, evalStdString("group", time));

        std::vector<std::string> skipped;

        hvdb::Interrupter boss("Creating VDB LoD pyramid");
        GA_RWHandleS name_h(gdp, GA_ATTRIB_PRIMITIVE, "name");

        const auto lodMode = evalInt("lod", 0, 0);
        if (lodMode == 0) {

            const bool reuseName = evalInt("reuse", 0, 0) > 0;
            MultiResGridFractionalOp<1> op( float(evalFloat("level", 0, time)) );
            for (hvdb::VdbPrimIterator it(gdp, group); it; ++it) {

                if (boss.wasInterrupted()) return error();

                if (name_h.isValid())
                    it->getGrid().setName(static_cast<const char *>(name_h.get(it->getMapOffset())));

                if (!it->getGrid().transform().isLinear()) {
                    skipped.push_back(it->getGrid().getName());
                    continue;
                }

                hvdb::GEOvdbApply<hvdb::VolumeGridTypes>(**it, op);

                if (boss.wasInterrupted()) return error();

                if (reuseName) op.outputGrid->setName( it->getGrid().getName() );

                hvdb::createVdbPrimitive(*gdp, op.outputGrid);

                gdp->destroyPrimitiveOffset(it->getMapOffset(), /*and_points=*/true);
            }

        } else if (lodMode == 1) {

            const float start = float(evalFloat("range", 0, time));
            const float end = float(evalFloat("range", 1, time));
            const float step = float(evalFloat("range", 2, time));

            if (!isValidRange(start, end, step)) {
                addError(SOP_MESSAGE, "Invalid range, make sure that "
                    "start <= end and the step size is a positive number.");
                return error();
            }

            MultiResGridRangeOp<1> op( start, end, step, boss );
            for (hvdb::VdbPrimIterator it(gdp, group); it; ++it) {

                if (boss.wasInterrupted()) return error();

                if (name_h.isValid())
                    it->getGrid().setName(static_cast<const char *>(name_h.get(it->getMapOffset())));

                if (!it->getGrid().transform().isLinear()) {
                    skipped.push_back(it->getGrid().getName());
                    continue;
                }

                hvdb::GEOvdbApply<hvdb::VolumeGridTypes>(**it, op);

                if (boss.wasInterrupted()) return error();

                for (size_t i=0; i< op.outputGrids.size(); ++i) {
                    hvdb::createVdbPrimitive(*gdp, op.outputGrids[i]);
                }

                gdp->destroyPrimitiveOffset(it->getMapOffset(), /*and_points=*/true);
            }
        } else if (lodMode == 2) {

            MultiResGridIntegerOp op( evalInt("count", 0, time) );
            for (hvdb::VdbPrimIterator it(gdp, group); it; ++it) {

                if (boss.wasInterrupted()) return error();

                if (name_h.isValid())
                    it->getGrid().setName(static_cast<const char *>(name_h.get(it->getMapOffset())));

                if (!it->getGrid().transform().isLinear()) {
                    skipped.push_back(it->getGrid().getName());
                    continue;
                }

                hvdb::GEOvdbApply<hvdb::VolumeGridTypes>(**it, op);

                if (boss.wasInterrupted()) return error();

                for (size_t i=0; i< op.outputGrids->size(); ++i) {
                    hvdb::createVdbPrimitive(*gdp, op.outputGrids->at(i));
                }

                gdp->destroyPrimitiveOffset(it->getMapOffset(), /*and_points=*/true);
            }

        } else {
            addError(SOP_MESSAGE, "Invalid LOD option.");
        }

        if (!skipped.empty()) {
            addWarning(SOP_MESSAGE, ("Unable to process grid(s): " +
                hboost::algorithm::join(skipped, ", ")).c_str());
        }

    } catch (std::exception& e) {
        addError(SOP_MESSAGE, e.what());
    }

    return error();
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "ros/ros.h"
#include "ram_msgs/Buoys.h"
#include <vector>

using namespace cv;
using namespace std;

Mat frame;
Mat hsv_frame, gray;
vector<Mat> hsv_channels;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
Mat drawing;

/** @function thresh_callback */
void thresh_callback(int, void*) {
    Mat canny_output;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    vector<Vec3f> circles;
    Mat blurred;

    // Detect edges using canny
    Canny(hsv_frame, canny_output, thresh, thresh*2, 3);

    /* GaussianBlur( hsv_channels[2], blurred, Size(9, 9), 0, 0 );
    HoughCircles( blurred, circles, CV_HOUGH_GRADIENT, 2, blurred.rows/4, 400, 50, 0, 0 );
    printf("%d", circles.size());
    */
    // Find contours
    findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // Draw contours
    drawing = Mat::zeros(canny_output.size(), CV_8UC3);
    for(int i = 0; i < contours.size(); i++) {
         Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255));
         drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
    }

    // Show in a window
    namedWindow("Contours", CV_WINDOW_AUTOSIZE);
    imshow("Contours", drawing);
}

int main(int argc, char*argv[]) {

    if(argc != 2){
        cout << "wrong number of arguments dummy, call \"a.out test_video\"" << endl;
        return 0;
    }

    //Publisher for circle locations
    ros::init(argc,argv,"circle_centers");
    ros::NodeHandle n;

    ros::Publisher circ_pub = n.advertise<ram_msgs::Buoys>("circle_locations", 1000);

    // Read image
    VideoCapture cap = VideoCapture( argv[1] );
    cap >> frame;

    Mat im_with_keypoints;
    std::vector<KeyPoint> keypoints;

    while(!frame.empty()) {
	// Convert the frame into hsv, then split it into channels
	cvtColor(frame, hsv_frame, CV_BGR2HSV);
	hsv_channels.clear();
	split(hsv_frame, hsv_channels);

	namedWindow("HSV", CV_WINDOW_AUTOSIZE);
	imshow("HSV",hsv_frame);
       	// GaussianBlur(hsv, hsv, Size(15, 15), 2, 2 );

        /// Create Window
        char* source_window = "Source";
        namedWindow(source_window, CV_WINDOW_AUTOSIZE);
        imshow(source_window, frame);

        createTrackbar(" Canny thresh:", "Source", &thresh, max_thresh, thresh_callback);
        thresh_callback(0, 0);

	cvtColor(drawing, gray, CV_BGR2GRAY);
	GaussianBlur(gray, gray, Size(15,15), 2, 2);
	namedWindow("drawings,gray", CV_WINDOW_AUTOSIZE);
	imshow("drawings,gray",gray);

	//Finds the locations of the circles and drwas them on the original image
        vector<Vec3f> circles;
        HoughCircles(gray, circles, CV_HOUGH_GRADIENT,2, gray.rows/4, thresh * 2, 82 );

	ram_msgs::Buoys buoy;
	//Hopefully there arent more than 10 circles the HoughCircles picks up
	std::vector<double> xs;
	std::vector<double> ys;
	std::vector<double> zs;
	//circ_pub.publish();

        waitKey(0);
        for(size_t i = 0; i < circles.size(); i++) {
                 Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
                 int radius = cvRound(circles[i][2]);
                 // draw the circle center
                 circle(frame, center, 3, Scalar(0,255,0), -1, 8, 0 );
                 // draw the circle outline
                 circle(frame, center, radius, Scalar(0,0,255), 3, 8, 0 );

		 xs.push_back(circles[i][0]);
		 ys.push_back(circles[i][1]);
		 zs.push_back(circles[i][2]);
         }

	buoy.x = xs;
	buoy.y = ys;
	buoy.z = zs;

	circ_pub.publish(buoy);

	namedWindow("circles", 1);
	imshow("circles", frame);

        waitKey(0);
        cap >> frame;
    }
}
<commit_msg>cleaned up a little updated canny_tuner (not much)<commit_after>#include <stdio.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include "ros/ros.h"
#include "ram_msgs/Buoys.h"
#include <vector>

using namespace cv;
using namespace std;

Mat frame;
Mat hsv_frame, gray;
vector<Mat> hsv_channels;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
Mat drawing;

/** @function thresh_callback */
void thresh_callback(int, void*) {
    Mat canny_output;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    vector<Vec3f> circles;
    Mat blurred;

    // Detect edges using canny
    Canny(hsv_frame, canny_output, thresh, thresh*2, 3);

    /* GaussianBlur( hsv_channels[2], blurred, Size(9, 9), 0, 0 );
    HoughCircles( blurred, circles, CV_HOUGH_GRADIENT, 2, blurred.rows/4, 400, 50, 0, 0 );
    printf("%d", circles.size());
    */
    // Find contours
    findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    // Draw contours
    drawing = Mat::zeros(canny_output.size(), CV_8UC3);
    for(int i = 0; i < contours.size(); i++) {
         Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255));
         drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
    }

    // Show in a window
    namedWindow("Contours", CV_WINDOW_AUTOSIZE);
    imshow("Contours", drawing);
}

int main(int argc, char*argv[]) {

    if(argc != 2){
        cout << "wrong number of arguments dummy, call \"a.out test_video\"" << endl;
        return 0;
    }

    //Publisher for circle locations
    ros::init(argc,argv,"circle_centers");
    ros::NodeHandle n;

    ros::Publisher circ_pub = n.advertise<ram_msgs::Buoys>("circle_locations", 1000);

    // Read image
    VideoCapture cap = VideoCapture( argv[1] );
    cap >> frame;

    Mat im_with_keypoints;
    std::vector<KeyPoint> keypoints;

    while(!frame.empty()) {
	// Convert the frame into hsv, then split it into channels
	cvtColor(frame, hsv_frame, CV_BGR2HSV);
	hsv_channels.clear();
	split(hsv_frame, hsv_channels);

	namedWindow("HSV", CV_WINDOW_AUTOSIZE);
	imshow("HSV",hsv_frame);
       	// GaussianBlur(hsv, hsv, Size(15, 15), 2, 2 );

        /// Create Window
        char* source_window = "Source";
        namedWindow(source_window, CV_WINDOW_AUTOSIZE);
        imshow(source_window, frame);

        createTrackbar(" Canny thresh:", "Source", &thresh, max_thresh, thresh_callback);
        thresh_callback(0, 0);

	cvtColor(drawing, gray, CV_BGR2GRAY);
	GaussianBlur(gray, gray, Size(15,15), 2, 2);
	namedWindow("drawings,gray", CV_WINDOW_AUTOSIZE);
	imshow("drawings,gray",gray);

	//Finds the locations of the circles and drwas them on the original image
        vector<Vec3f> circles;
        HoughCircles(gray, circles, CV_HOUGH_GRADIENT,2, gray.rows/4, thresh * 2, 82 );

	ram_msgs::Buoys buoy;
	//Hopefully there arent more than 10 circles the HoughCircles picks up
	std::vector<double> xs;
	std::vector<double> ys;
	std::vector<double> zs;

        waitKey(0);
        for(size_t i = 0; i < circles.size(); i++) {
                 Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
                 int radius = cvRound(circles[i][2]);
                 // draw the circle center
                 circle(frame, center, 3, Scalar(0,255,0), -1, 8, 0 );
                 // draw the circle outline
                 circle(frame, center, radius, Scalar(0,0,255), 3, 8, 0 );

		 xs.push_back(circles[i][0]);
		 ys.push_back(circles[i][1]);
		 zs.push_back(circles[i][2]);
         }

	buoy.x = xs;
	buoy.y = ys;
	buoy.z = zs;

	circ_pub.publish(buoy);

	namedWindow("circles", 1);
	imshow("circles", frame);

        waitKey(0);
        cap >> frame;
    }
}
<|endoftext|>


<commit_before>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

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

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "applicationcomponents.h"

#include <QBoxLayout>
#include <QLabel>
#include <QVariant>
#include <QWidget>
#include <QWidgetAction>

#include "availablepagesview.h"
#include "availablesourcesview.h"
#include "datasourcecombobox.h"
#include "editorview.h"
#include "pageview.h"

#include "presentation/applicationmodel.h"

using namespace Widgets;

ApplicationComponents::ApplicationComponents(QWidget *parent, ApplicationMode mode)
    : QObject(parent),
      m_model(0),
      m_parent(parent),
      m_availableSourcesView(0),
      m_availablePagesView(0),
      m_pageView(0),
      m_editorView(0),
      m_noteCombo(0),
      m_taskCombo(0),
      m_mode(mode)
{
}

QObject *ApplicationComponents::model() const
{
    return m_model;
}

AvailableSourcesView *ApplicationComponents::availableSourcesView() const
{
    if (!m_availableSourcesView) {
        auto availableSourcesView = new AvailableSourcesView(m_parent);
        if (m_model) {
            availableSourcesView->setModel(m_model->property("availableSources").value<QObject*>());
            if (m_mode == NotesOnly) {
                availableSourcesView->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
                connect(m_model, SIGNAL(defaultNoteDataSourceChanged(Domain::DataSource::Ptr)),
                        availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
            } else if (m_mode == TasksOnly) {
                availableSourcesView->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
                connect(m_model, SIGNAL(defaultTaskDataSourceChanged(Domain::DataSource::Ptr)),
                        availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
            } else {
                availableSourcesView->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
                connect(m_model, SIGNAL(defaultTaskDataSourceChanged(Domain::DataSource::Ptr)),
                        availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
                //TODO decide wether to set task or note source depending on source type?
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
            }
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_availableSourcesView = availableSourcesView;
    }

    return m_availableSourcesView;
}

AvailablePagesView *ApplicationComponents::availablePagesView() const
{
    if (!m_availablePagesView) {
        auto availablePagesView = new AvailablePagesView(m_parent);
        if (m_model) {
            availablePagesView->setModel(m_model->property("availablePages").value<QObject*>());
            availablePagesView->setProjectSourcesModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_availablePagesView = availablePagesView;

        connect(self->m_availablePagesView, SIGNAL(currentPageChanged(QObject*)),
                self, SLOT(onCurrentPageChanged(QObject*)));
    }

    return m_availablePagesView;
}

PageView *ApplicationComponents::pageView() const
{
    if (!m_pageView) {
        auto pageView = new PageView(m_parent, m_mode == NotesOnly ? PageView::NotesOnly : PageView::TasksOnly);
        if (m_model) {
            pageView->setModel(m_model->property("currentPage").value<QObject*>());
            connect(m_model, SIGNAL(currentPageChanged(QObject*)),
                    pageView, SLOT(setModel(QObject*)));
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_pageView = pageView;

        connect(self->m_pageView, SIGNAL(currentArtifactChanged(Domain::Artifact::Ptr)),
                self, SLOT(onCurrentArtifactChanged(Domain::Artifact::Ptr)));
    }

    return m_pageView;
}

EditorView *ApplicationComponents::editorView() const
{
    if (!m_editorView) {
        auto editorView = new EditorView(m_parent);
        if (m_model) {
            editorView->setModel(m_model->property("editor").value<QObject*>());
        }

        auto self = const_cast<ApplicationComponents*>(this);
        self->m_editorView = editorView;
    }

    return m_editorView;
}

QList<QAction *> ApplicationComponents::configureActions() const
{
    if (m_configureActions.isEmpty()) {
        QList<QAction*> actions;

        if (m_mode == TasksAndNotes) {
            auto widget = new QWidget;
            widget->setLayout(new QHBoxLayout);
            widget->layout()->addWidget(new QLabel(tr("Default task source")));
            widget->layout()->addWidget(defaultTaskSourceCombo());

            auto comboAction = new QWidgetAction(m_parent);
            comboAction->setObjectName("zanshin_settings_task_sources");
            comboAction->setDefaultWidget(widget);
            actions << comboAction;

            widget = new QWidget;
            widget->setLayout(new QHBoxLayout);
            widget->layout()->addWidget(new QLabel(tr("Default note source")));
            widget->layout()->addWidget(defaultNoteSourceCombo());

            comboAction = new QWidgetAction(m_parent);
            comboAction->setObjectName("zanshin_settings_note_sources");
            comboAction->setDefaultWidget(widget);
            actions << comboAction;
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_configureActions = actions;
    }

    return m_configureActions;
}

DataSourceComboBox *ApplicationComponents::defaultNoteSourceCombo() const
{
    if (!m_noteCombo) {
        auto combo = new DataSourceComboBox(m_parent);
        combo->setObjectName("noteSourceCombo");
        combo->setFixedWidth(300);
        if (m_model) {
            combo->setModel(m_model->property("noteSourcesModel").value<QAbstractItemModel*>());
            combo->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
            connect(combo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_noteCombo = combo;
    }

    return m_noteCombo;
}

DataSourceComboBox *ApplicationComponents::defaultTaskSourceCombo() const
{
    if (!m_taskCombo) {
        auto combo = new DataSourceComboBox(m_parent);
        combo->setObjectName("taskSourceCombo");
        combo->setFixedWidth(300);
        if (m_model) {
            combo->setModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
            combo->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
            connect(combo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_taskCombo = combo;
    }

    return m_taskCombo;
}

void ApplicationComponents::setModel(QObject *model)
{
    if (m_model == model)
        return;

    m_model = model;

    if (m_availableSourcesView) {
        m_availableSourcesView->setModel(m_model->property("availableSources").value<QObject*>());
        m_availableSourcesView->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
    }

    if (m_availablePagesView) {
        m_availablePagesView->setModel(m_model->property("availablePages").value<QObject*>());
        m_availablePagesView->setProjectSourcesModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
    }

    if (m_pageView) {
        m_pageView->setModel(m_model->property("currentPage").value<QObject*>());
        connect(m_model, SIGNAL(currentPageChanged(QObject*)),
                m_pageView, SLOT(setModel(QObject*)));
    }

    if (m_editorView)
        m_editorView->setModel(m_model->property("editor").value<QObject*>());

    if (m_noteCombo) {
        m_noteCombo->setModel(m_model->property("noteSourcesModel").value<QAbstractItemModel*>());
        m_noteCombo->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
        connect(m_noteCombo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
    }

    if (m_taskCombo) {
        m_taskCombo->setModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
        m_taskCombo->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
        connect(m_noteCombo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
    }
}

void ApplicationComponents::onCurrentPageChanged(QObject *page)
{
    m_model->setProperty("currentPage", QVariant::fromValue(page));

    QObject *editorModel = m_model->property("editor").value<QObject*>();
    if (editorModel)
        editorModel->setProperty("artifact", QVariant::fromValue(Domain::Artifact::Ptr()));
}

void ApplicationComponents::onCurrentArtifactChanged(const Domain::Artifact::Ptr &artifact)
{
    auto editorModel = m_model->property("editor").value<QObject*>();
    editorModel->setProperty("artifact", QVariant::fromValue(artifact));
}
<commit_msg>Depending on what comes first we may have to reconnect<commit_after>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

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

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "applicationcomponents.h"

#include <QBoxLayout>
#include <QLabel>
#include <QVariant>
#include <QWidget>
#include <QWidgetAction>

#include "availablepagesview.h"
#include "availablesourcesview.h"
#include "datasourcecombobox.h"
#include "editorview.h"
#include "pageview.h"

#include "presentation/applicationmodel.h"

using namespace Widgets;

ApplicationComponents::ApplicationComponents(QWidget *parent, ApplicationMode mode)
    : QObject(parent),
      m_model(0),
      m_parent(parent),
      m_availableSourcesView(0),
      m_availablePagesView(0),
      m_pageView(0),
      m_editorView(0),
      m_noteCombo(0),
      m_taskCombo(0),
      m_mode(mode)
{
}

QObject *ApplicationComponents::model() const
{
    return m_model;
}

AvailableSourcesView *ApplicationComponents::availableSourcesView() const
{
    if (!m_availableSourcesView) {
        auto availableSourcesView = new AvailableSourcesView(m_parent);
        if (m_model) {
            availableSourcesView->setModel(m_model->property("availableSources").value<QObject*>());
            if (m_mode == NotesOnly) {
                availableSourcesView->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
                connect(m_model, SIGNAL(defaultNoteDataSourceChanged(Domain::DataSource::Ptr)),
                        availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
            } else if (m_mode == TasksOnly) {
                availableSourcesView->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
                connect(m_model, SIGNAL(defaultTaskDataSourceChanged(Domain::DataSource::Ptr)),
                        availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
            } else {
                availableSourcesView->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
                connect(m_model, SIGNAL(defaultTaskDataSourceChanged(Domain::DataSource::Ptr)),
                        availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
                //TODO decide wether to set task or note source depending on source type?
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
                connect(availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                        m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
            }
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_availableSourcesView = availableSourcesView;
    }

    return m_availableSourcesView;
}

AvailablePagesView *ApplicationComponents::availablePagesView() const
{
    if (!m_availablePagesView) {
        auto availablePagesView = new AvailablePagesView(m_parent);
        if (m_model) {
            availablePagesView->setModel(m_model->property("availablePages").value<QObject*>());
            availablePagesView->setProjectSourcesModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_availablePagesView = availablePagesView;

        connect(self->m_availablePagesView, SIGNAL(currentPageChanged(QObject*)),
                self, SLOT(onCurrentPageChanged(QObject*)));
    }

    return m_availablePagesView;
}

PageView *ApplicationComponents::pageView() const
{
    if (!m_pageView) {
        auto pageView = new PageView(m_parent, m_mode == NotesOnly ? PageView::NotesOnly : PageView::TasksOnly);
        if (m_model) {
            pageView->setModel(m_model->property("currentPage").value<QObject*>());
            connect(m_model, SIGNAL(currentPageChanged(QObject*)),
                    pageView, SLOT(setModel(QObject*)));
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_pageView = pageView;

        connect(self->m_pageView, SIGNAL(currentArtifactChanged(Domain::Artifact::Ptr)),
                self, SLOT(onCurrentArtifactChanged(Domain::Artifact::Ptr)));
    }

    return m_pageView;
}

EditorView *ApplicationComponents::editorView() const
{
    if (!m_editorView) {
        auto editorView = new EditorView(m_parent);
        if (m_model) {
            editorView->setModel(m_model->property("editor").value<QObject*>());
        }

        auto self = const_cast<ApplicationComponents*>(this);
        self->m_editorView = editorView;
    }

    return m_editorView;
}

QList<QAction *> ApplicationComponents::configureActions() const
{
    if (m_configureActions.isEmpty()) {
        QList<QAction*> actions;

        if (m_mode == TasksAndNotes) {
            auto widget = new QWidget;
            widget->setLayout(new QHBoxLayout);
            widget->layout()->addWidget(new QLabel(tr("Default task source")));
            widget->layout()->addWidget(defaultTaskSourceCombo());

            auto comboAction = new QWidgetAction(m_parent);
            comboAction->setObjectName("zanshin_settings_task_sources");
            comboAction->setDefaultWidget(widget);
            actions << comboAction;

            widget = new QWidget;
            widget->setLayout(new QHBoxLayout);
            widget->layout()->addWidget(new QLabel(tr("Default note source")));
            widget->layout()->addWidget(defaultNoteSourceCombo());

            comboAction = new QWidgetAction(m_parent);
            comboAction->setObjectName("zanshin_settings_note_sources");
            comboAction->setDefaultWidget(widget);
            actions << comboAction;
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_configureActions = actions;
    }

    return m_configureActions;
}

DataSourceComboBox *ApplicationComponents::defaultNoteSourceCombo() const
{
    if (!m_noteCombo) {
        auto combo = new DataSourceComboBox(m_parent);
        combo->setObjectName("noteSourceCombo");
        combo->setFixedWidth(300);
        if (m_model) {
            combo->setModel(m_model->property("noteSourcesModel").value<QAbstractItemModel*>());
            combo->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
            connect(combo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_noteCombo = combo;
    }

    return m_noteCombo;
}

DataSourceComboBox *ApplicationComponents::defaultTaskSourceCombo() const
{
    if (!m_taskCombo) {
        auto combo = new DataSourceComboBox(m_parent);
        combo->setObjectName("taskSourceCombo");
        combo->setFixedWidth(300);
        if (m_model) {
            combo->setModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
            combo->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
            connect(combo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
        }

        ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
        self->m_taskCombo = combo;
    }

    return m_taskCombo;
}

void ApplicationComponents::setModel(QObject *model)
{
    if (m_model == model)
        return;

    m_model = model;

    if (m_availableSourcesView) {
        m_availableSourcesView->setModel(m_model->property("availableSources").value<QObject*>());
        if (m_mode == NotesOnly) {
            m_availableSourcesView->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
            connect(m_model, SIGNAL(defaultNoteDataSourceChanged(Domain::DataSource::Ptr)),
                    m_availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
            connect(m_availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
        } else if (m_mode == TasksOnly) {
            m_availableSourcesView->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
            connect(m_model, SIGNAL(defaultTaskDataSourceChanged(Domain::DataSource::Ptr)),
                    m_availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
            connect(m_availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
        } else {
            m_availableSourcesView->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
            connect(m_model, SIGNAL(defaultTaskDataSourceChanged(Domain::DataSource::Ptr)),
                    m_availableSourcesView, SLOT(setDefaultSource(Domain::DataSource::Ptr)));
            //TODO decide wether to set task or note source depending on source type?
            connect(m_availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
            connect(m_availableSourcesView, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                    m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
        }
    }

    if (m_availablePagesView) {
        m_availablePagesView->setModel(m_model->property("availablePages").value<QObject*>());
        m_availablePagesView->setProjectSourcesModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
    }

    if (m_pageView) {
        m_pageView->setModel(m_model->property("currentPage").value<QObject*>());
        connect(m_model, SIGNAL(currentPageChanged(QObject*)),
                m_pageView, SLOT(setModel(QObject*)));
    }

    if (m_editorView)
        m_editorView->setModel(m_model->property("editor").value<QObject*>());

    if (m_noteCombo) {
        m_noteCombo->setModel(m_model->property("noteSourcesModel").value<QAbstractItemModel*>());
        m_noteCombo->setDefaultSourceProperty(m_model, "defaultNoteDataSource");
        connect(m_noteCombo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                m_model, SLOT(setDefaultNoteDataSource(Domain::DataSource::Ptr)));
    }

    if (m_taskCombo) {
        m_taskCombo->setModel(m_model->property("taskSourcesModel").value<QAbstractItemModel*>());
        m_taskCombo->setDefaultSourceProperty(m_model, "defaultTaskDataSource");
        connect(m_noteCombo, SIGNAL(sourceActivated(Domain::DataSource::Ptr)),
                m_model, SLOT(setDefaultTaskDataSource(Domain::DataSource::Ptr)));
    }
}

void ApplicationComponents::onCurrentPageChanged(QObject *page)
{
    m_model->setProperty("currentPage", QVariant::fromValue(page));

    QObject *editorModel = m_model->property("editor").value<QObject*>();
    if (editorModel)
        editorModel->setProperty("artifact", QVariant::fromValue(Domain::Artifact::Ptr()));
}

void ApplicationComponents::onCurrentArtifactChanged(const Domain::Artifact::Ptr &artifact)
{
    auto editorModel = m_model->property("editor").value<QObject*>();
    editorModel->setProperty("artifact", QVariant::fromValue(artifact));
}
<|endoftext|>


<commit_before>#include <os>
#include <net/inet4>
#include <math.h>
#include <iostream>
#include <sstream>
#include <net/dhcp/dh4client.hpp>

using namespace std::chrono;

// An IP-stack object
std::unique_ptr<net::Inet4<VirtioNet> > inet;

void Service::start() {

  // Assign a driver (VirtioNet) to a network interface (eth0)
  // @note: We could determine the appropirate driver dynamically, but then we'd
  // have to include all the drivers into the image, which  we want to avoid.
  Nic<VirtioNet>& eth0 = Dev::eth<0,VirtioNet>();

  // Bring up a network stack, attached to the nic
  inet = std::make_unique<net::Inet4<VirtioNet> >(eth0);

  printf("Size of IP-stack: %i bytes \n",sizeof(inet));
  printf("Service IP address: %s \n", inet->ip_addr().str().c_str());

  // Set up a TCP server on port 80
  net::TCP::Socket& sock =  inet->tcp().bind(80);

  printf("SERVICE: %i open ports in TCP @ %p \n",
      inet->tcp().openPorts(), &(inet->tcp()));

  srand(OS::cycles_since_boot());

  sock.onConnect([](net::TCP::Socket& conn){
      printf("SERVICE got data: %s \n",conn.read(1024).c_str());

      int color = rand();
      std::stringstream stream;

      /* HTML Fonts */
      std::string ubuntu_medium  = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; ";
      std::string ubuntu_normal  = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; ";
      std::string ubuntu_light  = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; ";

      /* HTML */
      stream << ""
	     << "<link href='https://fonts.googleapis.com/css?family=Ubuntu:500,300' rel='stylesheet' type='text/css'>"
	     << ""
	     << "<h1 style= \"color: " << "#" << std::hex << (color >> 8) << "\">"
	     <<  "IncludeOS
"
	     <<  "
Now speaks TCP!
"
	// .... generate more dynamic content
	     << "
  ...and can improvise http. With limitations of course, but it's been easier than expected so far
"
	     << "
 © 2015, Oslo and Akershus University College of Applied Sciences "
	     << "\n";

      /* HTTP-header */
      std::string html = stream.str();
      std::string header="HTTP/1.1 200 OK \n "				\
	"Date: Mon, 01 Jan 1970 00:00:01 GMT \n"			\
	"Server: IncludeOS prototype 4.0 \n"				\
	"Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n"		\
	"Content-Type: text/html; charset=UTF-8 \n"			\
	"Content-Length: "+std::to_string(html.size())+"\n"		\
	"Accept-Ranges: bytes\n"					\
	"Connection: close\n\n";

      conn.write(header);
      conn.write(html);

      // We don't have to actively close when the http-header says "Connection: close"
      //conn.close();

    });

  printf("*** TEST SERVICE STARTED *** \n");

}
<commit_msg>Demo service has static IP + DHCP<commit_after>#include <os>
#include <net/inet4>
#include <math.h>
#include <iostream>
#include <sstream>
#include <net/dhcp/dh4client.hpp>

using namespace std::chrono;

// An IP-stack object
std::unique_ptr<net::Inet4<VirtioNet> > inet;

void Service::start() {

  // Assign a driver (VirtioNet) to a network interface (eth0)
  // @note: We could determine the appropirate driver dynamically, but then we'd
  // have to include all the drivers into the image, which  we want to avoid.
  Nic<VirtioNet>& eth0 = Dev::eth<0,VirtioNet>();

  // Bring up a network stack, attached to the nic
  inet = std::make_unique<net::Inet4<VirtioNet> >(eth0);

  // Static configuration, until we (possibly) get DHCP
  inet->network_config( {{ 10,0,0,42 }},      // IP
			{{ 255,255,255,0 }},  // Netmask
			{{ 10,0,0,1 }},       // Gateway
			{{ 8,8,8,8 }} );      // DNS

  printf("Size of IP-stack: %i b \n",sizeof(inet));
  printf("Service IP address: %s \n", inet->ip_addr().str().c_str());

  // Set up a TCP server on port 80
  net::TCP::Socket& sock =  inet->tcp().bind(80);

  printf("SERVICE: %i open ports in TCP @ %p \n",
      inet->tcp().openPorts(), &(inet->tcp()));

  srand(OS::cycles_since_boot());

  sock.onConnect([](net::TCP::Socket& conn){
      printf("SERVICE got data: %s \n",conn.read(1024).c_str());

      int color = rand();
      std::stringstream stream;

      /* HTML Fonts */
      std::string ubuntu_medium  = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; ";
      std::string ubuntu_normal  = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; ";
      std::string ubuntu_light  = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; ";

      /* HTML */
      stream << ""
	     << "<link href='https://fonts.googleapis.com/css?family=Ubuntu:500,300' rel='stylesheet' type='text/css'>"
	     << ""
	     << "<h1 style= \"color: " << "#" << std::hex << (color >> 8) << "\">"
	     <<  "IncludeOS
"
	     <<  "
Now speaks TCP!
"
	// .... generate more dynamic content
	     << "
  ...and can improvise http. With limitations of course, but it's been easier than expected so far
"
	     << "
 © 2015, Oslo and Akershus University College of Applied Sciences "
	     << "\n";

      /* HTTP-header */
      std::string html = stream.str();
      std::string header="HTTP/1.1 200 OK \n "				\
	"Date: Mon, 01 Jan 1970 00:00:01 GMT \n"			\
	"Server: IncludeOS prototype 4.0 \n"				\
	"Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n"		\
	"Content-Type: text/html; charset=UTF-8 \n"			\
	"Content-Length: "+std::to_string(html.size())+"\n"		\
	"Accept-Ranges: bytes\n"					\
	"Connection: close\n\n";

      conn.write(header);
      conn.write(html);

      // We don't have to actively close when the http-header says "Connection: close"
      //conn.close();

    });

  printf("*** TEST SERVICE STARTED *** \n");

}
<|endoftext|>