<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_ukf.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_UKF_HPP
#define FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_UKF_HPP

#include <map>
#include <tuple>
#include <memory>

#include <fl/util/meta.hpp>
#include <fl/util/traits.hpp>

#include <fl/exception/exception.hpp>
#include <fl/filter/filter_interface.hpp>
#include <fl/filter/gaussian/point_set.hpp>

namespace fl
{

// Forward declarations
template <typename...> class GaussianFilter;

/**
 * GaussianFilter Traits
 */
template <typename ProcessModel,
          typename ObservationModel,
          typename PointSetTransform>
struct Traits<GaussianFilter<ProcessModel, ObservationModel, PointSetTransform>>
{
    typedef GaussianFilter<
                ProcessModel,
                ObservationModel,
                PointSetTransform
            > Filter;

    /*
     * Required concept (interface) types
     *
     * - Ptr
     * - State
     * - Input
     * - Observation
     * - StateDistribution
     */
    typedef std::shared_ptr<Filter> Ptr;
    typedef typename Traits<ProcessModel>::State State;
    typedef typename Traits<ProcessModel>::Input Input;
    typedef typename Traits<ObservationModel>::Observation Observation;

    /**
     * Represents the underlying distribution of the estimated state. In
     * case of a Point Based Kalman filter, the distribution is a simple
     * Gaussian with the dimension of the \c State.
     */
    typedef Gaussian<State> StateDistribution;

    /** \cond INTERNAL */
    typedef typename Traits<ProcessModel>::Noise StateNoise;
    typedef typename Traits<ObservationModel>::Noise ObsrvNoise;

    enum
    {
        /**
         * Represents the total number of points required by the point set
         * transform.
         *
         * The number of points is a function of the joint Gaussian of which we
         * compute the transform. In this case the joint Gaussian consists of
         * the Gaussian of the state, the state noise Gaussian and the
         * observation noise Gaussian. The latter two are needed since we assume
         * models with non-additive noise.
         *
         * The resulting number of points determined by the employed transform
         * passed via \c PointSetTransform. If on or more of the marginal
         * Gaussian sizes is dynamic, the number of points is dynamic as well.
         * That is, the number of points cannot be known at compile time and
         * will be allocated dynamically on run time.
         */
        NumberOfPoints = PointSetTransform::number_of_points(
                            JoinSizes<
                                State::RowsAtCompileTime,
                                StateNoise::RowsAtCompileTime,
                                ObsrvNoise::RowsAtCompileTime
                            >::Size)
    };

    typedef PointSet<State, NumberOfPoints> StatePointSet;
    typedef PointSet<Observation, NumberOfPoints> ObsrvPointSet;
    typedef PointSet<StateNoise, NumberOfPoints> StateNoisePointSet;
    typedef PointSet<ObsrvNoise, NumberOfPoints> ObsrvNoisePointSet;

    /**
     * \brief KalmanGain Matrix
     */
    typedef Eigen::Matrix<
                typename StateDistribution::Scalar,
                State::RowsAtCompileTime,
                Observation::RowsAtCompileTime
            > KalmanGain;
    /** \endcond */
};

/**
 * GaussianFilter represents all filters based on Gaussian distributed systems.
 * This includes the Kalman Filter and filters using non-linear models such as
 * Sigma Point Kalman Filter family.
 *
 * \tparam ProcessModel
 * \tparam ObservationModel
 *
 * \ingroup filters
 * \ingroup sigma_point_kalman_filters
 */
template<
    typename ProcessModel,
    typename ObservationModel,
    typename PointSetTransform
>
class GaussianFilter<ProcessModel, ObservationModel, PointSetTransform>
    :
    /* Implement the conceptual filter interface */
    public FilterInterface<
              GaussianFilter<ProcessModel, ObservationModel, PointSetTransform>>

{
protected:
    /** \cond INTERNAL */
    typedef GaussianFilter<ProcessModel, ObservationModel, PointSetTransform> This;
    typedef typename Traits<This>::KalmanGain KalmanGain;
    typedef typename Traits<This>::StateNoise StateNoise;
    typedef typename Traits<This>::ObsrvNoise ObsrvNoise;
    typedef typename Traits<This>::StatePointSet StatePointSet;
    typedef typename Traits<This>::ObsrvPointSet ObsrvPointSet;
    typedef typename Traits<This>::StateNoisePointSet StateNoisePointSet;
    typedef typename Traits<This>::ObsrvNoisePointSet ObsrvNoisePointSet;
    /** \endcond */

public:
    /* public concept interface types */
    typedef typename Traits<This>::State State;
    typedef typename Traits<This>::Input Input;
    typedef typename Traits<This>::Observation Obsrv;
    typedef typename Traits<This>::StateDistribution StateDistribution;

public:
    /**
     * Creates a Gaussian filter
     *
     * \param process_model         Process model instance
     * \param Obsrv_model           Obsrv model instance
     * \param point_set_transform   Point set tranfrom such as the unscented
     *                              transform
     */
    GaussianFilter(const std::shared_ptr<ProcessModel>& process_model,
                   const std::shared_ptr<ObservationModel>& Obsrv_model,
                   const std::shared_ptr<PointSetTransform>& point_set_transform)
        : process_model_(process_model),
          obsrv_model_(Obsrv_model),
          point_set_transform_(point_set_transform),
          /*
           * Set the augmented Gaussian dimension.
           *
           * The global dimension is dimension of the augmented Gaussian which
           * consists of state Gaussian, state noise Gaussian and the
           * observation noise Gaussian.
           */
          global_dimension_(process_model_->state_dimension()
                            + process_model_->noise_dimension()
                            + obsrv_model_->noise_dimension()),
          /*
           * Initialize the points-set Gaussian (e.g. sigma points) of the
           * \em state noise. The number of points is determined by the
           * augmented Gaussian with the dimension  global_dimension_
           */
          X_Q(process_model_->noise_dimension(),
              PointSetTransform::number_of_points(global_dimension_)),

          /*
           * Initialize the points-set Gaussian (e.g. sigma points) of the
           * \em observation noise. The number of points is determined by the
           * augmented Gaussian with the dimension global_dimension_
           */
          X_R(obsrv_model_->noise_dimension(),
              PointSetTransform::number_of_points(global_dimension_))
    {
        /*
         * pre-compute the state noise points from the standard Gaussian
         * distribution with the dimension of the state noise and store the
         * points in the X_Q PointSet
         *
         * The points are computet for the marginal Q of the global Gaussian
         * with the dimension global_dimension_ as depecited below
         *
         *    [ P  0  0 ]
         * -> [ 0  Q  0 ] -> [X_Q[1]  X_Q[2] ... X_Q[p]]
         *    [ 0  0  R ]
         *
         * p is the number of points determined be the transform type
         *
         * The transform takes the global dimension (dim(P) + dim(Q) + dim(R))
         * and the dimension offset dim(P) as parameters.
         */
        point_set_transform_->forward(
            Gaussian<StateNoise>(process_model_->noise_dimension()),
            global_dimension_,
            process_model_->state_dimension(),
            X_Q);

        /*
         * pre-compute the observation noise points from the standard Gaussian
         * distribution with the dimension of the observation noise and store
         * the points in the X_R PointSet
         *
         * The points are computet for the marginal R of the global Gaussian
         * with the dimension global_dimension_ as depecited below
         *
         *    [ P  0  0 ]
         *    [ 0  Q  0 ]
         * -> [ 0  0  R ] -> [X_R[1]  X_R[2] ... X_R[p]]
         *
         * again p is the number of points determined be the transform type
         *
         * The transform takes the global dimension (dim(P) + dim(Q) + dim(R))
         * and the dimension offset dim(P) + dim(Q) as parameters.
         */
        point_set_transform_->forward(
            Gaussian<ObsrvNoise>(obsrv_model_->noise_dimension()),
            global_dimension_,
            process_model_->state_dimension()
            + process_model_->noise_dimension(),
            X_R);

        /*
         * Setup the point set of the observation predictions
         */
        const size_t point_count =
                PointSetTransform::number_of_points(global_dimension_);
        X_y.resize(point_count);
        X_y.dimension(obsrv_model_->obsrv_dimension());
    }

    /**
     * \copydoc FilterInterface::predict
     */
    virtual void predict(double delta_time,
                         const Input& input,
                         const StateDistribution& prior_dist,
                         StateDistribution& predicted_dist)
    {
        /*
         * Compute the state points from the given prior state Gaussian
         * distribution and store the points in the X_r PointSet
         *
         * The points are computet for the marginal R of the global Gaussian
         * with the dimension global_dimension_ as depecited below
         *
         * -> [ P  0  0 ] -> [X_r[1]  X_r[2] ... X_r[p]]
         *    [ 0  Q  0 ]
         *    [ 0  0  R ]
         *
         * The transform takes the global dimension (dim(P) + dim(Q) + dim(R))
         * and the dimension offset 0 as parameters.
         */
        point_set_transform_->forward(prior_dist,
                                      global_dimension_,
                                      0,
                                      X_r);

        /*
         * Predict each point X_r[i] and store the prediction back in X_r[i]
         *
         * X_r[i] = f(X_r[i], X_Q[i], u)
         */
        const size_t point_count = X_r.count_points();
        for (size_t i = 0; i < point_count; ++i)
        {
            X_r.point(i, process_model_->predict_state(delta_time,
                                                       X_r.point(i),
                                                       X_Q.point(i),
                                                       input));
        }

        /*
         * Obtain the centered points matrix of the prediction. The columns of
         * this matrix are the predicted points with zero mean. That is, the
         * sum of the columns in P is zero.
         *
         * P = [X_r[1]-mu_r  X_r[2]-mu_r  ... X_r[n]-mu_r]
         *
         * with weighted mean
         *
         * mu_r = Sum w_mean[i] X_r[i]
         */
        auto&& X = X_r.centered_points();

        /*
         * Obtain the weights of point as a vector
         *
         * W = [w_cov[1]  w_cov[2]  ... w_cov[n]]
         *
         * Note that the covariance weights are used.
         */
        auto&& W = X_r.covariance_weights_vector();

        /*
         * Compute and set the moments
         *
         * The first moment is simply the weighted mean of points.
         * The second centered moment is determined by
         *
         * C = Sum W[i,i] * (X_r[i]-mu_r)(X_r[i]-mu_r)^T
         *   = P * W * P^T
         *
         * given that W is the diagonal matrix
         */
        predicted_dist.mean(X_r.mean());
        predicted_dist.covariance(X * W.asDiagonal() * X.transpose());
    }

    /**
     * \copydoc FilterInterface::update
     */
    virtual void update(const Obsrv& y,
                        const StateDistribution& predicted_dist,
                        StateDistribution& posterior_dist)
    {
        point_set_transform_->forward(predicted_dist,
                                      global_dimension_,
                                      0,
                                      X_r);

        const size_t point_count = X_r.count_points();
        for (size_t i = 0; i < point_count; ++i)
        {
            X_y.point(i, obsrv_model_->predict_observation(X_r.point(i),
                                                           X_R.point(i)));
        }

        auto W = X_r.covariance_weights_vector();
        auto X = X_r.centered_points();
        auto Y = X_y.centered_points();

        auto cov_xx = X * W.asDiagonal() * X.transpose();
        auto cov_yy = Y * W.asDiagonal() * Y.transpose();
        auto cov_xy = X * W.asDiagonal() * Y.transpose();

        const KalmanGain& K = cov_xy * cov_yy.inverse();

        posterior_dist.mean(X_r.mean() + K * (y - X_y.mean()));
        posterior_dist.covariance(cov_xx - K * cov_yy * K.transpose());
    }

    /**
     * \copydoc FilterInterface::predict_and_update
     */
    virtual void predict_and_update(double delta_time,
                                    const Input& input,
                                    const Obsrv& observation,
                                    const StateDistribution& prior_dist,
                                    StateDistribution& posterior_dist)
    {
        predict(delta_time, input, prior_dist, posterior_dist);
        update(observation, posterior_dist, posterior_dist);
    }

protected:
    std::shared_ptr<ProcessModel> process_model_;
    std::shared_ptr<ObservationModel> obsrv_model_;
    std::shared_ptr<PointSetTransform> point_set_transform_;

    /** \cond INTERNAL */
    /**
     * \brief The global dimension is dimension of the augmented Gaussian which
     * consists of state Gaussian, state noise Gaussian and the
     * observation noise Gaussian.
     */
    const size_t global_dimension_;

    /**
     * \brief Represents the point-set of the state
     */
    StatePointSet X_r;

    /**
     * \brief Represents the point-set of the observation
     */
    ObsrvPointSet X_y;

    /**
     * \brief Represents the points-set Gaussian (e.g. sigma points) of the
     * \em state noise. The number of points is determined by the augmented
     * Gaussian with the dimension #global_dimension_
     */
    StateNoisePointSet X_Q;

    /**
     * \brief Represents the points-set Gaussian (e.g. sigma points) of the
     * \em observation noise. The number of points is determined by the
     * augmented Gaussian with the dimension #global_dimension_
     */
    ObsrvNoisePointSet X_R;
    /** \endcond */
};

}

#endif
<commit_msg>fixed predict_observation call<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file gaussian_filter_ukf.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_UKF_HPP
#define FL__FILTER__GAUSSIAN__GAUSSIAN_FILTER_UKF_HPP

#include <map>
#include <tuple>
#include <memory>

#include <fl/util/meta.hpp>
#include <fl/util/traits.hpp>

#include <fl/exception/exception.hpp>
#include <fl/filter/filter_interface.hpp>
#include <fl/filter/gaussian/point_set.hpp>

namespace fl
{

// Forward declarations
template <typename...> class GaussianFilter;

/**
 * GaussianFilter Traits
 */
template <typename ProcessModel,
          typename ObservationModel,
          typename PointSetTransform>
struct Traits<GaussianFilter<ProcessModel, ObservationModel, PointSetTransform>>
{
    typedef GaussianFilter<
                ProcessModel,
                ObservationModel,
                PointSetTransform
            > Filter;

    /*
     * Required concept (interface) types
     *
     * - Ptr
     * - State
     * - Input
     * - Observation
     * - StateDistribution
     */
    typedef std::shared_ptr<Filter> Ptr;
    typedef typename Traits<ProcessModel>::State State;
    typedef typename Traits<ProcessModel>::Input Input;
    typedef typename Traits<ObservationModel>::Observation Observation;

    /**
     * Represents the underlying distribution of the estimated state. In
     * case of a Point Based Kalman filter, the distribution is a simple
     * Gaussian with the dimension of the \c State.
     */
    typedef Gaussian<State> StateDistribution;

    /** \cond INTERNAL */
    typedef typename Traits<ProcessModel>::Noise StateNoise;
    typedef typename Traits<ObservationModel>::Noise ObsrvNoise;

    enum
    {
        /**
         * Represents the total number of points required by the point set
         * transform.
         *
         * The number of points is a function of the joint Gaussian of which we
         * compute the transform. In this case the joint Gaussian consists of
         * the Gaussian of the state, the state noise Gaussian and the
         * observation noise Gaussian. The latter two are needed since we assume
         * models with non-additive noise.
         *
         * The resulting number of points determined by the employed transform
         * passed via \c PointSetTransform. If on or more of the marginal
         * Gaussian sizes is dynamic, the number of points is dynamic as well.
         * That is, the number of points cannot be known at compile time and
         * will be allocated dynamically on run time.
         */
        NumberOfPoints = PointSetTransform::number_of_points(
                            JoinSizes<
                                State::RowsAtCompileTime,
                                StateNoise::RowsAtCompileTime,
                                ObsrvNoise::RowsAtCompileTime
                            >::Size)
    };

    typedef PointSet<State, NumberOfPoints> StatePointSet;
    typedef PointSet<Observation, NumberOfPoints> ObsrvPointSet;
    typedef PointSet<StateNoise, NumberOfPoints> StateNoisePointSet;
    typedef PointSet<ObsrvNoise, NumberOfPoints> ObsrvNoisePointSet;

    /**
     * \brief KalmanGain Matrix
     */
    typedef Eigen::Matrix<
                typename StateDistribution::Scalar,
                State::RowsAtCompileTime,
                Observation::RowsAtCompileTime
            > KalmanGain;
    /** \endcond */
};

/**
 * GaussianFilter represents all filters based on Gaussian distributed systems.
 * This includes the Kalman Filter and filters using non-linear models such as
 * Sigma Point Kalman Filter family.
 *
 * \tparam ProcessModel
 * \tparam ObservationModel
 *
 * \ingroup filters
 * \ingroup sigma_point_kalman_filters
 */
template<
    typename ProcessModel,
    typename ObservationModel,
    typename PointSetTransform
>
class GaussianFilter<ProcessModel, ObservationModel, PointSetTransform>
    :
    /* Implement the conceptual filter interface */
    public FilterInterface<
              GaussianFilter<ProcessModel, ObservationModel, PointSetTransform>>

{
protected:
    /** \cond INTERNAL */
    typedef GaussianFilter<ProcessModel, ObservationModel, PointSetTransform> This;
    typedef typename Traits<This>::KalmanGain KalmanGain;
    typedef typename Traits<This>::StateNoise StateNoise;
    typedef typename Traits<This>::ObsrvNoise ObsrvNoise;
    typedef typename Traits<This>::StatePointSet StatePointSet;
    typedef typename Traits<This>::ObsrvPointSet ObsrvPointSet;
    typedef typename Traits<This>::StateNoisePointSet StateNoisePointSet;
    typedef typename Traits<This>::ObsrvNoisePointSet ObsrvNoisePointSet;
    /** \endcond */

public:
    /* public concept interface types */
    typedef typename Traits<This>::State State;
    typedef typename Traits<This>::Input Input;
    typedef typename Traits<This>::Observation Obsrv;
    typedef typename Traits<This>::StateDistribution StateDistribution;

public:
    /**
     * Creates a Gaussian filter
     *
     * \param process_model         Process model instance
     * \param Obsrv_model           Obsrv model instance
     * \param point_set_transform   Point set tranfrom such as the unscented
     *                              transform
     */
    GaussianFilter(const std::shared_ptr<ProcessModel>& process_model,
                   const std::shared_ptr<ObservationModel>& Obsrv_model,
                   const std::shared_ptr<PointSetTransform>& point_set_transform)
        : process_model_(process_model),
          obsrv_model_(Obsrv_model),
          point_set_transform_(point_set_transform),
          /*
           * Set the augmented Gaussian dimension.
           *
           * The global dimension is dimension of the augmented Gaussian which
           * consists of state Gaussian, state noise Gaussian and the
           * observation noise Gaussian.
           */
          global_dimension_(process_model_->state_dimension()
                            + process_model_->noise_dimension()
                            + obsrv_model_->noise_dimension()),
          /*
           * Initialize the points-set Gaussian (e.g. sigma points) of the
           * \em state noise. The number of points is determined by the
           * augmented Gaussian with the dimension  global_dimension_
           */
          X_Q(process_model_->noise_dimension(),
              PointSetTransform::number_of_points(global_dimension_)),

          /*
           * Initialize the points-set Gaussian (e.g. sigma points) of the
           * \em observation noise. The number of points is determined by the
           * augmented Gaussian with the dimension global_dimension_
           */
          X_R(obsrv_model_->noise_dimension(),
              PointSetTransform::number_of_points(global_dimension_))
    {
        /*
         * pre-compute the state noise points from the standard Gaussian
         * distribution with the dimension of the state noise and store the
         * points in the X_Q PointSet
         *
         * The points are computet for the marginal Q of the global Gaussian
         * with the dimension global_dimension_ as depecited below
         *
         *    [ P  0  0 ]
         * -> [ 0  Q  0 ] -> [X_Q[1]  X_Q[2] ... X_Q[p]]
         *    [ 0  0  R ]
         *
         * p is the number of points determined be the transform type
         *
         * The transform takes the global dimension (dim(P) + dim(Q) + dim(R))
         * and the dimension offset dim(P) as parameters.
         */
        point_set_transform_->forward(
            Gaussian<StateNoise>(process_model_->noise_dimension()),
            global_dimension_,
            process_model_->state_dimension(),
            X_Q);

        /*
         * pre-compute the observation noise points from the standard Gaussian
         * distribution with the dimension of the observation noise and store
         * the points in the X_R PointSet
         *
         * The points are computet for the marginal R of the global Gaussian
         * with the dimension global_dimension_ as depecited below
         *
         *    [ P  0  0 ]
         *    [ 0  Q  0 ]
         * -> [ 0  0  R ] -> [X_R[1]  X_R[2] ... X_R[p]]
         *
         * again p is the number of points determined be the transform type
         *
         * The transform takes the global dimension (dim(P) + dim(Q) + dim(R))
         * and the dimension offset dim(P) + dim(Q) as parameters.
         */
        point_set_transform_->forward(
            Gaussian<ObsrvNoise>(obsrv_model_->noise_dimension()),
            global_dimension_,
            process_model_->state_dimension()
            + process_model_->noise_dimension(),
            X_R);

        /*
         * Setup the point set of the observation predictions
         */
        const size_t point_count =
                PointSetTransform::number_of_points(global_dimension_);
        X_y.resize(point_count);
        X_y.dimension(obsrv_model_->obsrv_dimension());
    }

    /**
     * \copydoc FilterInterface::predict
     */
    virtual void predict(double delta_time,
                         const Input& input,
                         const StateDistribution& prior_dist,
                         StateDistribution& predicted_dist)
    {
        /*
         * Compute the state points from the given prior state Gaussian
         * distribution and store the points in the X_r PointSet
         *
         * The points are computet for the marginal R of the global Gaussian
         * with the dimension global_dimension_ as depecited below
         *
         * -> [ P  0  0 ] -> [X_r[1]  X_r[2] ... X_r[p]]
         *    [ 0  Q  0 ]
         *    [ 0  0  R ]
         *
         * The transform takes the global dimension (dim(P) + dim(Q) + dim(R))
         * and the dimension offset 0 as parameters.
         */
        point_set_transform_->forward(prior_dist,
                                      global_dimension_,
                                      0,
                                      X_r);

        /*
         * Predict each point X_r[i] and store the prediction back in X_r[i]
         *
         * X_r[i] = f(X_r[i], X_Q[i], u)
         */
        const size_t point_count = X_r.count_points();
        for (size_t i = 0; i < point_count; ++i)
        {
            X_r.point(i, process_model_->predict_state(delta_time,
                                                       X_r.point(i),
                                                       X_Q.point(i),
                                                       input));
        }

        /*
         * Obtain the centered points matrix of the prediction. The columns of
         * this matrix are the predicted points with zero mean. That is, the
         * sum of the columns in P is zero.
         *
         * P = [X_r[1]-mu_r  X_r[2]-mu_r  ... X_r[n]-mu_r]
         *
         * with weighted mean
         *
         * mu_r = Sum w_mean[i] X_r[i]
         */
        auto&& X = X_r.centered_points();

        /*
         * Obtain the weights of point as a vector
         *
         * W = [w_cov[1]  w_cov[2]  ... w_cov[n]]
         *
         * Note that the covariance weights are used.
         */
        auto&& W = X_r.covariance_weights_vector();

        /*
         * Compute and set the moments
         *
         * The first moment is simply the weighted mean of points.
         * The second centered moment is determined by
         *
         * C = Sum W[i,i] * (X_r[i]-mu_r)(X_r[i]-mu_r)^T
         *   = P * W * P^T
         *
         * given that W is the diagonal matrix
         */
        predicted_dist.mean(X_r.mean());
        predicted_dist.covariance(X * W.asDiagonal() * X.transpose());
    }

    /**
     * \copydoc FilterInterface::update
     */
    virtual void update(const Obsrv& y,
                        const StateDistribution& predicted_dist,
                        StateDistribution& posterior_dist)
    {
        point_set_transform_->forward(predicted_dist,
                                      global_dimension_,
                                      0,
                                      X_r);

        const size_t point_count = X_r.count_points();
        for (size_t i = 0; i < point_count; ++i)
        {
            X_y.point(i, obsrv_model_->predict_observation(X_r.point(i),
                                                           X_R.point(i),
                                                           0 /* delta time */));
        }

        auto W = X_r.covariance_weights_vector();
        auto X = X_r.centered_points();
        auto Y = X_y.centered_points();

        auto cov_xx = X * W.asDiagonal() * X.transpose();
        auto cov_yy = Y * W.asDiagonal() * Y.transpose();
        auto cov_xy = X * W.asDiagonal() * Y.transpose();

        const KalmanGain& K = cov_xy * cov_yy.inverse();

        posterior_dist.mean(X_r.mean() + K * (y - X_y.mean()));
        posterior_dist.covariance(cov_xx - K * cov_yy * K.transpose());
    }

    /**
     * \copydoc FilterInterface::predict_and_update
     */
    virtual void predict_and_update(double delta_time,
                                    const Input& input,
                                    const Obsrv& observation,
                                    const StateDistribution& prior_dist,
                                    StateDistribution& posterior_dist)
    {
        predict(delta_time, input, prior_dist, posterior_dist);
        update(observation, posterior_dist, posterior_dist);
    }

protected:
    std::shared_ptr<ProcessModel> process_model_;
    std::shared_ptr<ObservationModel> obsrv_model_;
    std::shared_ptr<PointSetTransform> point_set_transform_;

    /** \cond INTERNAL */
    /**
     * \brief The global dimension is dimension of the augmented Gaussian which
     * consists of state Gaussian, state noise Gaussian and the
     * observation noise Gaussian.
     */
    const size_t global_dimension_;

    /**
     * \brief Represents the point-set of the state
     */
    StatePointSet X_r;

    /**
     * \brief Represents the point-set of the observation
     */
    ObsrvPointSet X_y;

    /**
     * \brief Represents the points-set Gaussian (e.g. sigma points) of the
     * \em state noise. The number of points is determined by the augmented
     * Gaussian with the dimension #global_dimension_
     */
    StateNoisePointSet X_Q;

    /**
     * \brief Represents the points-set Gaussian (e.g. sigma points) of the
     * \em observation noise. The number of points is determined by the
     * augmented Gaussian with the dimension #global_dimension_
     */
    ObsrvNoisePointSet X_R;
    /** \endcond */
};

}

#endif
<|endoftext|>


<commit_before>/******************************************************************************
 * plane_bind.cpp - bindings for Ogre::Plane
 ******************************************************************************
 * This file is part of
 *     __ __              _
 *    / // /_____ ____   (_)
 *   / // // ___// __ \ / /
 *  / // // /__ / /_/ // /
 * /_//_/ \___/ \____//_/
 *
 * Low Level C Ogre Interface (llcoi)
 *
 * See http://code.google.com/p/llcoi/ for more information.
 *
 * Copyright (c) 2011, Llcoi Team
 *
 * License: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/
#include "ogre_interface.h"

#include <OgreRoot.h>
#include <OgrePlane.h>
<commit_msg>create/delete methods<commit_after>/******************************************************************************
 * plane_bind.cpp - bindings for Ogre::Plane
 ******************************************************************************
 * This file is part of
 *     __ __              _
 *    / // /_____ ____   (_)
 *   / // // ___// __ \ / /
 *  / // // /__ / /_/ // /
 * /_//_/ \___/ \____//_/
 *
 * Low Level C Ogre Interface (llcoi)
 *
 * See http://code.google.com/p/llcoi/ for more information.
 *
 * Copyright (c) 2011, Llcoi Team
 *
 * License: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/
#include "ogre_interface.h"

#include <OgreRoot.h>
#include <OgrePlane.h>

PlaneHandle create_plane()
{
    Ogre::Plane* plane = new Ogre::Plane;
    return reinterpret_cast<PlaneHandle>(plane);

}

void destroy_plane(PlaneHandle handle)
{
    Ogre::Plane* plane = reinterpret_cast<Ogre::Plane*>(handle);
    delete plane;
}
<|endoftext|>


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

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "enquery/execution.h"
#include "enquery/executive.h"
#include "enquery/status.h"
#include "enquery/testing.h"

using ::enquery::Execution;
using ::enquery::Executive;
using ::enquery::Future;
using ::enquery::Status;

namespace enquery {

// Execution implementation that always fails. The constructor accepts a
// a pointer-to-bool, which is set to 'false' on construction, and set to
// 'true' on destruction; this can be used by the test to determine the
// correct behavior of Executive's optional mechanism for taking ownership
// of the Execution instance that's passed during creation.
class Task;
class FailingExecution : public Execution {
 public:
  explicit FailingExecution(bool* set_when_destroyed)
      : set_when_destroyed_(set_when_destroyed) {
    *set_when_destroyed_ = false;
  }

  virtual ~FailingExecution() { *set_when_destroyed_ = true; }

  virtual Status Execute(Task*) {  // NOLINT
    return Status::MakeError("test", "failed to execute");
  }

 private:
  bool* set_when_destroyed_;
};

}  // namespace enquery

// Sample function for unit test (simply negates integer that's passed.)
int negate(int x) { return -x; }

void test_default_use() {
  const int input_value = 42;

  // Create an Executive with default options; pass NULL to use execute
  // everything on the curren thread. The boolean parameter indicates
  // that Executive should own the 'Execution' object, however when
  // NULL is passed, the current thread executive is used, and the
  // Executive *always* owns that.
  Executive* executive = Executive::Create(NULL, true);

  // Create an empty future, to be populated later via Submit()
  Future<int> future_result;
  ASSERT_FALSE(future_result.Valid());

  // Submit a task; in this case, we're making a call to the 'negate'
  // type, passing input_value as the argument; if successful,
  // 'future_result' is populated with a future that will eventually
  // hold the result of the calculation.
  Status status = executive->Submit(negate, input_value, &future_result);

  // We should succeed
  ASSERT_TRUE(status.IsSuccess());

  // We should get the correct answer
  ASSERT_EQUALS(future_result.GetValue(), negate(input_value));

  delete executive;
}

// Test failing execution while simultaneously testing that the executive
// properly cleans up its "execution method" when so configured.
void test_failing_use_with_ownership() {
  const int input_value = 42;

  // First, create an execution method that always fails.
  bool destroyed = false;
  Execution* exm = new enquery::FailingExecution(&destroyed);

  // Create an executive that's configured to take ownership of
  // the execution method that's passed in.
  Executive* executive = Executive::Create(exm, true);

  // Create an empty future to hold the result.
  Future<int> future_result;
  ASSERT_FALSE(future_result.Valid());

  // Submit the task for execution, which should fail fail.
  Status status = executive->Submit(negate, input_value, &future_result);
  ASSERT_FALSE(status.IsSuccess());
  ASSERT_FALSE(future_result.Valid());

  // Delete the executive.
  delete executive;

  // Assert that Execution owned by Executive was actually destroyed.
  ASSERT_TRUE(destroyed);
}

// Test that the executive does not delete the "execution method" when
// so configured.
void test_not_taking_ownership() {
  bool destroyed = false;
  Execution* exm = new enquery::FailingExecution(&destroyed);
  Executive* executive = Executive::Create(exm, false);
  delete executive;
  ASSERT_FALSE(destroyed);
  delete exm;
}

int main(int argc, char* argv[]) {
  test_default_use();
  test_failing_use_with_ownership();
  test_not_taking_ownership();
  return EXIT_SUCCESS;
}
<commit_msg>fix typo in comment<commit_after>// Copyright 2015 The Enquery Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. See the AUTHORS file for names of
// contributors.

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "enquery/execution.h"
#include "enquery/executive.h"
#include "enquery/status.h"
#include "enquery/testing.h"

using ::enquery::Execution;
using ::enquery::Executive;
using ::enquery::Future;
using ::enquery::Status;

namespace enquery {

// Execution implementation that always fails. The constructor accepts a
// a pointer-to-bool, which is set to 'false' on construction, and set to
// 'true' on destruction; this can be used by the test to determine the
// correct behavior of Executive's optional mechanism for taking ownership
// of the Execution instance that's passed during creation.
class Task;
class FailingExecution : public Execution {
 public:
  explicit FailingExecution(bool* set_when_destroyed)
      : set_when_destroyed_(set_when_destroyed) {
    *set_when_destroyed_ = false;
  }

  virtual ~FailingExecution() { *set_when_destroyed_ = true; }

  virtual Status Execute(Task*) {  // NOLINT
    return Status::MakeError("test", "failed to execute");
  }

 private:
  bool* set_when_destroyed_;
};

}  // namespace enquery

// Sample function for unit test (simply negates integer that's passed.)
int negate(int x) { return -x; }

void test_default_use() {
  const int input_value = 42;

  // Create an Executive with default options; pass NULL to use execute
  // everything on the current thread. The boolean parameter indicates
  // that Executive should own the 'Execution' object, however when
  // NULL is passed, the current thread executive is used, and the
  // Executive *always* owns that.
  Executive* executive = Executive::Create(NULL, true);

  // Create an empty future, to be populated later via Submit()
  Future<int> future_result;
  ASSERT_FALSE(future_result.Valid());

  // Submit a task; in this case, we're making a call to the 'negate'
  // type, passing input_value as the argument; if successful,
  // 'future_result' is populated with a future that will eventually
  // hold the result of the calculation.
  Status status = executive->Submit(negate, input_value, &future_result);

  // We should succeed
  ASSERT_TRUE(status.IsSuccess());

  // We should get the correct answer
  ASSERT_EQUALS(future_result.GetValue(), negate(input_value));

  delete executive;
}

// Test failing execution while simultaneously testing that the executive
// properly cleans up its "execution method" when so configured.
void test_failing_use_with_ownership() {
  const int input_value = 42;

  // First, create an execution method that always fails.
  bool destroyed = false;
  Execution* exm = new enquery::FailingExecution(&destroyed);

  // Create an executive that's configured to take ownership of
  // the execution method that's passed in.
  Executive* executive = Executive::Create(exm, true);

  // Create an empty future to hold the result.
  Future<int> future_result;
  ASSERT_FALSE(future_result.Valid());

  // Submit the task for execution, which should fail fail.
  Status status = executive->Submit(negate, input_value, &future_result);
  ASSERT_FALSE(status.IsSuccess());
  ASSERT_FALSE(future_result.Valid());

  // Delete the executive.
  delete executive;

  // Assert that Execution owned by Executive was actually destroyed.
  ASSERT_TRUE(destroyed);
}

// Test that the executive does not delete the "execution method" when
// so configured.
void test_not_taking_ownership() {
  bool destroyed = false;
  Execution* exm = new enquery::FailingExecution(&destroyed);
  Executive* executive = Executive::Create(exm, false);
  delete executive;
  ASSERT_FALSE(destroyed);
  delete exm;
}

int main(int argc, char* argv[]) {
  test_default_use();
  test_failing_use_with_ownership();
  test_not_taking_ownership();
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before><commit_msg>just a test...<commit_after><|endoftext|>


<commit_before>//
//  Created by Bradley Austin Davis on 2016/03/19
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

#pragma once

#include "common.hpp"

namespace vkx {

    // Version information for Vulkan is stored in a single 32 bit integer
    // with individual bits representing the major, minor and patch versions.
    // The maximum possible major and minor version is 512 (look out nVidia)
    // while the maximum possible patch version is 2048
    struct Version {
        Version() : major(0), minor(0), patch(0) {
        }
        Version(uint32_t version) : Version() {
            *this = version;
        }

        Version& operator =(uint32_t version) {
            memcpy(this, &version, sizeof(uint32_t));
            return *this;
        }

        operator uint32_t() const {
            uint32_t result;
            memcpy(&result, this, sizeof(uint32_t));
        }

        std::string toString() const {
            std::stringstream buffer;
            buffer << major << "." << minor << "." << patch;
            return buffer.str();
        }

        const uint32_t patch : 12;
        const uint32_t minor : 10;
        const uint32_t major : 10;

    };
}<commit_msg>fix name clash with gcc macro<commit_after>//
//  Created by Bradley Austin Davis on 2016/03/19
//
//  Distributed under the Apache License, Version 2.0.
//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

#pragma once

#include "common.hpp"

namespace vkx {

    // Version information for Vulkan is stored in a single 32 bit integer
    // with individual bits representing the major, minor and patch versions.
    // The maximum possible major and minor version is 512 (look out nVidia)
    // while the maximum possible patch version is 2048
    struct Version {
        Version() : vulkan_major(0), vulkan_minor(0), vulkan_patch(0) {
        }
        Version(uint32_t version) : Version() {
            *this = version;
        }

        Version& operator =(uint32_t version) {
            memcpy(this, &version, sizeof(uint32_t));
            return *this;
        }

        operator uint32_t() const {
            uint32_t result;
            memcpy(&result, this, sizeof(uint32_t));
        }

        std::string toString() const {
            std::stringstream buffer;
            buffer << vulkan_major << "." << vulkan_minor << "." << vulkan_patch;
            return buffer.str();
        }

        const uint32_t vulkan_patch : 12;
        const uint32_t vulkan_minor : 10;
        const uint32_t vulkan_major : 10;

    };
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: chaptercollator.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2003-03-26 10:54:38 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <assert.h>

// prevent internal compiler error with MSVC6SP3
#include <stl/utility>

#include <chaptercollator.hxx>
#include <com/sun/star/i18n/KCharacterType.hpp>
#ifndef _COM_SUN_STAR_I18N_PARSERESULT_HPP_
#include <com/sun/star/i18n/ParseResult.hpp>
#endif

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::i18n;
using namespace ::rtl;

ChapterCollator::ChapterCollator( const Reference < XMultiServiceFactory >& rxMSF ) : CollatorImpl(rxMSF)
{
    if ( rxMSF.is()) {
        Reference < XInterface > xI =
        rxMSF->createInstance( OUString::createFromAscii("com.sun.star.i18n.CharacterClassification"));
        if ( xI.is() )
            xI->queryInterface(::getCppuType((const Reference< XCharacterClassification>*)0)) >>= cclass;
    }
}

ChapterCollator::~ChapterCollator()
{
}

sal_Int32 SAL_CALL
ChapterCollator::compareString( const OUString& s1, const OUString& s2) throw(RuntimeException)
{
    return compareSubstring(s1, 0, s1.getLength(),  s2, 0, s2.getLength());
}

#define DIGIT KCharacterType::DIGIT

sal_Int32 SAL_CALL
ChapterCollator::compareSubstring( const OUString& str1, sal_Int32 off1, sal_Int32 len1,
    const OUString& str2, sal_Int32 off2, sal_Int32 len2) throw(RuntimeException)
{
    if( len1 <= 1 || len2 <= 1 || ! cclass.is() )
        return CollatorImpl::compareSubstring( str1, off1,  len1, str2, off2, len2 );

    sal_Int32 i1, i2;
    for (i1 = len1; i1 && (cclass->getCharacterType(str1, off1+i1-1, nLocale) & DIGIT); i1--);
    for (i2 = len2; i2 && (cclass->getCharacterType(str2, off2+i2-1, nLocale) & DIGIT); i2--);

    sal_Int32 ans = CollatorImpl::compareSubstring(str1, off1, i1, str2, off2, i2);
    if( ans != 0 )
        return ans;

    OUString &aAddAllowed = OUString::createFromAscii("?");
    ParseResult res1, res2;
    // Bug #100323#, since parseAnyToken does not take length as parameter, we have to copy
    // it to a temp. string.
    OUString s1 = str1.copy(off1+i1, len1-i1), s2 = str2.copy(off2+i2, len2-i2);
    res1 = cclass->parseAnyToken( s1, 0, nLocale, DIGIT, aAddAllowed, DIGIT, aAddAllowed );
    res2 = cclass->parseAnyToken( s2, 0, nLocale, DIGIT, aAddAllowed, DIGIT, aAddAllowed );

    return res1.Value == res2.Value ? 0 : res1.Value > res2.Value ? 1 : -1;
}

const sal_Char *cChapCollator = "com.sun.star.i18n.ChapterCollator";

OUString SAL_CALL
ChapterCollator::getImplementationName() throw( RuntimeException )
{
    return OUString::createFromAscii(cChapCollator);
}

sal_Bool SAL_CALL
ChapterCollator::supportsService(const rtl::OUString& rServiceName) throw( RuntimeException )
{
    return !rServiceName.compareToAscii(cChapCollator);
}

Sequence< OUString > SAL_CALL
ChapterCollator::getSupportedServiceNames() throw( RuntimeException )
{
    Sequence< OUString > aRet(1);
    aRet[0] = OUString::createFromAscii(cChapCollator);
    return aRet;
}
<commit_msg>INTEGRATION: CWS dbgmacros1 (1.3.46); FILE MERGED 2003/04/09 11:54:43 kso 1.3.46.1: #108413# - debug macro unification.<commit_after>/*************************************************************************
 *
 *  $RCSfile: chaptercollator.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2003-04-15 17:07:52 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

// prevent internal compiler error with MSVC6SP3
#include <stl/utility>

#include <chaptercollator.hxx>
#include <com/sun/star/i18n/KCharacterType.hpp>
#ifndef _COM_SUN_STAR_I18N_PARSERESULT_HPP_
#include <com/sun/star/i18n/ParseResult.hpp>
#endif

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::i18n;
using namespace ::rtl;

ChapterCollator::ChapterCollator( const Reference < XMultiServiceFactory >& rxMSF ) : CollatorImpl(rxMSF)
{
    if ( rxMSF.is()) {
        Reference < XInterface > xI =
        rxMSF->createInstance( OUString::createFromAscii("com.sun.star.i18n.CharacterClassification"));
        if ( xI.is() )
            xI->queryInterface(::getCppuType((const Reference< XCharacterClassification>*)0)) >>= cclass;
    }
}

ChapterCollator::~ChapterCollator()
{
}

sal_Int32 SAL_CALL
ChapterCollator::compareString( const OUString& s1, const OUString& s2) throw(RuntimeException)
{
    return compareSubstring(s1, 0, s1.getLength(),  s2, 0, s2.getLength());
}

#define DIGIT KCharacterType::DIGIT

sal_Int32 SAL_CALL
ChapterCollator::compareSubstring( const OUString& str1, sal_Int32 off1, sal_Int32 len1,
    const OUString& str2, sal_Int32 off2, sal_Int32 len2) throw(RuntimeException)
{
    if( len1 <= 1 || len2 <= 1 || ! cclass.is() )
        return CollatorImpl::compareSubstring( str1, off1,  len1, str2, off2, len2 );

    sal_Int32 i1, i2;
    for (i1 = len1; i1 && (cclass->getCharacterType(str1, off1+i1-1, nLocale) & DIGIT); i1--);
    for (i2 = len2; i2 && (cclass->getCharacterType(str2, off2+i2-1, nLocale) & DIGIT); i2--);

    sal_Int32 ans = CollatorImpl::compareSubstring(str1, off1, i1, str2, off2, i2);
    if( ans != 0 )
        return ans;

    OUString &aAddAllowed = OUString::createFromAscii("?");
    ParseResult res1, res2;
    // Bug #100323#, since parseAnyToken does not take length as parameter, we have to copy
    // it to a temp. string.
    OUString s1 = str1.copy(off1+i1, len1-i1), s2 = str2.copy(off2+i2, len2-i2);
    res1 = cclass->parseAnyToken( s1, 0, nLocale, DIGIT, aAddAllowed, DIGIT, aAddAllowed );
    res2 = cclass->parseAnyToken( s2, 0, nLocale, DIGIT, aAddAllowed, DIGIT, aAddAllowed );

    return res1.Value == res2.Value ? 0 : res1.Value > res2.Value ? 1 : -1;
}

const sal_Char *cChapCollator = "com.sun.star.i18n.ChapterCollator";

OUString SAL_CALL
ChapterCollator::getImplementationName() throw( RuntimeException )
{
    return OUString::createFromAscii(cChapCollator);
}

sal_Bool SAL_CALL
ChapterCollator::supportsService(const rtl::OUString& rServiceName) throw( RuntimeException )
{
    return !rServiceName.compareToAscii(cChapCollator);
}

Sequence< OUString > SAL_CALL
ChapterCollator::getSupportedServiceNames() throw( RuntimeException )
{
    Sequence< OUString > aRet(1);
    aRet[0] = OUString::createFromAscii(cChapCollator);
    return aRet;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by the
 * Free Software Foundation; either version 3 of the License, or (at your
 * option) any later version.
 *
 * 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 Affero General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "Chat.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "Transmogrification.h"
#include "Tokenize.h"

using namespace Acore::ChatCommands;

class transmog_commandscript : public CommandScript
{
public:
    transmog_commandscript() : CommandScript("transmog_commandscript") { }

    ChatCommandTable GetCommands() const override
    {
        static ChatCommandTable addCollectionTable =
        {
            { "set", HandleAddTransmogItemSet,    SEC_MODERATOR, Console::Yes },
            { "",    HandleAddTransmogItem,       SEC_MODERATOR, Console::Yes },
        };

        static ChatCommandTable transmogTable =
        {
            { "add", addCollectionTable },
            { "",    HandleDisableTransMogVisual,   SEC_PLAYER,    Console::No },
            { "sync",    HandleSyncTransMogCommand, SEC_PLAYER,    Console::No },
        };

        static ChatCommandTable commandTable =
        {
            { "transmog", transmogTable },
        };

        return commandTable;
    }

    static bool HandleSyncTransMogCommand(ChatHandler* handler, char const* /*args*/)
    {
        Player* player = handler->GetPlayer();
        uint32 accountId = player->GetSession()->GetAccountId();
        handler->SendSysMessage(LANG_CMD_TRANSMOG_BEGIN_SYNC);
        for (uint32 itemId : sTransmogrification->collectionCache[accountId])
        {
            handler->PSendSysMessage("TRANSMOG_SYNC:%u", itemId);
        }
        handler->SendSysMessage(LANG_CMD_TRANSMOG_COMPLETE_SYNC);
        return true;
    }

    static bool HandleDisableTransMogVisual(ChatHandler* handler, bool hide)
    {
        Player* player = handler->GetPlayer();

        if (hide)
        {
            player->UpdatePlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG, 0);
            handler->SendSysMessage(LANG_CMD_TRANSMOG_SHOW);
        }
        else
        {
            player->UpdatePlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG, 1);
            handler->SendSysMessage(LANG_CMD_TRANSMOG_HIDE);
        }

        player->UpdateObjectVisibility();
        return true;
    }

    static bool HandleAddTransmogItem(ChatHandler* handler, Optional<PlayerIdentifier> player, ItemTemplate const* itemTemplate)
    {
        if (!sTransmogrification->GetUseCollectionSystem())
            return true;

        if (!sObjectMgr->GetItemTemplate(itemTemplate->ItemId))
        {
            handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemTemplate->ItemId);
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (!player)
        {
            player = PlayerIdentifier::FromTargetOrSelf(handler);
        }

        if (!player)
        {
            return false;
        }

        Player* target = player->GetConnectedPlayer();
        bool isNotConsole = handler->GetSession();
        bool suitableForTransmog;

        if (target)
        {
            suitableForTransmog = sTransmogrification->SuitableForTransmogrification(target, itemTemplate);
        }
        else
        {
            suitableForTransmog = sTransmogrification->SuitableForTransmogrification(player->GetGUID(), itemTemplate);
        }

        if (!sTransmogrification->GetTrackUnusableItems() && !suitableForTransmog)
        {
            handler->SendSysMessage(LANG_CMD_TRANSMOG_ADD_UNSUITABLE);
            handler->SetSentErrorMessage(true);
            return true;
        }

        if (itemTemplate->Class != ITEM_CLASS_ARMOR && itemTemplate->Class != ITEM_CLASS_WEAPON)
        {
            handler->SendSysMessage(LANG_CMD_TRANSMOG_ADD_FORBIDDEN);
            handler->SetSentErrorMessage(true);
            return true;
        }

        auto guid = player->GetGUID();
        uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid);
        uint32 itemId = itemTemplate->ItemId;

        std::stringstream tempStream;
        tempStream << std::hex << ItemQualityColors[itemTemplate->Quality];
        std::string itemQuality = tempStream.str();
        std::string itemName = itemTemplate->Name1;
        std::string playerName = player->GetName();
        std::string nameLink = handler->playerLink(playerName);

        if (sTransmogrification->AddCollectedAppearance(accountId, itemId))
        {
            // Notify target of new item in appearance collection
            if (target && !(target->GetPlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG).value) && !sTransmogrification->CanNeverTransmog(itemTemplate))
            {
                ChatHandler(target->GetSession()).PSendSysMessage(R"(|c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r has been added to your appearance collection.)", itemQuality.c_str(), itemId, itemName.c_str());
            }

            // Feedback of successful command execution to GM
            if (isNotConsole && target != handler->GetPlayer())
            {
                handler->PSendSysMessage(R"(|c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r has been added to the appearance collection of Player %s.)", itemQuality.c_str(), itemId, itemName.c_str(), nameLink);
            }

            CharacterDatabase.Execute("INSERT INTO custom_unlocked_appearances (account_id, item_template_id) VALUES ({}, {})", accountId, itemId);
        }
        else
        {
            // Feedback of failed command execution to GM
            if (isNotConsole)
            {
                handler->PSendSysMessage(R"(Player %s already has item |c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r in the appearance collection.)", nameLink, itemQuality.c_str(), itemId, itemName.c_str());
                handler->SetSentErrorMessage(true);
            }
        }

        return true;
    }

    static bool HandleAddTransmogItemSet(ChatHandler* handler, Optional<PlayerIdentifier> player, Variant<Hyperlink<itemset>, uint32> itemSetId)
    {
        if (!sTransmogrification->GetUseCollectionSystem())
            return true;

        if (!*itemSetId)
        {
            handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, uint32(itemSetId));
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (!player)
        {
            player = PlayerIdentifier::FromTargetOrSelf(handler);
        }

        if (!player)
        {
            return false;
        }

        Player* target = player->GetConnectedPlayer();
        ItemSetEntry const* set = sItemSetStore.LookupEntry(uint32(itemSetId));
        bool isNotConsole = handler->GetSession();

        if (!set)
        {
            handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, uint32(itemSetId));
            handler->SetSentErrorMessage(true);
            return false;
        }

        auto guid = player->GetGUID();
        CharacterCacheEntry const* playerData = sCharacterCache->GetCharacterCacheByGuid(guid);
        if (!playerData)
            return false;

        bool added = false;
        uint32 error = 0;
        uint32 itemId;
        uint32 accountId = playerData->AccountId;

        for (uint32 i = 0; i < MAX_ITEM_SET_ITEMS; ++i)
        {
            itemId = set->itemId[i];
            if (itemId)
            {
                ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
                if (itemTemplate)
                {
                    if (!sTransmogrification->GetTrackUnusableItems() && (
                            (target && !sTransmogrification->SuitableForTransmogrification(target, itemTemplate)) ||
                            !sTransmogrification->SuitableForTransmogrification(guid, itemTemplate)
                            ))
                    {
                        error = LANG_CMD_TRANSMOG_ADD_UNSUITABLE;
                        continue;
                    }
                    if (itemTemplate->Class != ITEM_CLASS_ARMOR && itemTemplate->Class != ITEM_CLASS_WEAPON)
                    {
                        error = LANG_CMD_TRANSMOG_ADD_FORBIDDEN;
                        continue;
                    }

                    if (sTransmogrification->AddCollectedAppearance(accountId, itemId))
                    {
                        CharacterDatabase.Execute("INSERT INTO custom_unlocked_appearances (account_id, item_template_id) VALUES ({}, {})", accountId, itemId);
                        added = true;
                    }
                }
            }
        }

        if (!added && error > 0)
        {
            handler->SendSysMessage(error);
            handler->SetSentErrorMessage(true);
            return true;
        }

        int locale = handler->GetSessionDbcLocale();
        std::string setName = set->name[locale];
        std::string nameLink = handler->playerLink(player->GetName());

        // Feedback of command execution to GM
        if (isNotConsole)
        {
            // Failed command execution
            if (!added)
            {
                handler->PSendSysMessage("Player %s already has ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r in the appearance collection.", nameLink, uint32(itemSetId), setName.c_str(), localeNames[locale]);
                handler->SetSentErrorMessage(true);
                return true;
            }

            // Successful command execution
            if (target != handler->GetPlayer())
            {
                handler->PSendSysMessage("ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r has been added to the appearance collection of Player %s.", uint32(itemSetId), setName.c_str(), localeNames[locale], nameLink);
            }
        }

        // Notify target of new item in appearance collection
        if (target && !(target->GetPlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG).value))
        {
            ChatHandler(target->GetSession()).PSendSysMessage("ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r has been added to your appearance collection.", uint32(itemSetId), setName.c_str(), localeNames[locale]);
        }

        return true;
    }
};

void AddSC_transmog_commandscript()
{
    new transmog_commandscript();
}
<commit_msg>fix: Fix sync command params to avoid deprecated build warning (#99)<commit_after>/*
 * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by the
 * Free Software Foundation; either version 3 of the License, or (at your
 * option) any later version.
 *
 * 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 Affero General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "Chat.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "Transmogrification.h"
#include "Tokenize.h"

using namespace Acore::ChatCommands;

class transmog_commandscript : public CommandScript
{
public:
    transmog_commandscript() : CommandScript("transmog_commandscript") { }

    ChatCommandTable GetCommands() const override
    {
        static ChatCommandTable addCollectionTable =
        {
            { "set", HandleAddTransmogItemSet,    SEC_MODERATOR, Console::Yes },
            { "",    HandleAddTransmogItem,       SEC_MODERATOR, Console::Yes },
        };

        static ChatCommandTable transmogTable =
        {
            { "add", addCollectionTable },
            { "",    HandleDisableTransMogVisual,   SEC_PLAYER,    Console::No },
            { "sync",    HandleSyncTransMogCommand, SEC_PLAYER,    Console::No },
        };

        static ChatCommandTable commandTable =
        {
            { "transmog", transmogTable },
        };

        return commandTable;
    }

    static bool HandleSyncTransMogCommand(ChatHandler* handler)
    {
        Player* player = handler->GetPlayer();
        uint32 accountId = player->GetSession()->GetAccountId();
        handler->SendSysMessage(LANG_CMD_TRANSMOG_BEGIN_SYNC);
        for (uint32 itemId : sTransmogrification->collectionCache[accountId])
        {
            handler->PSendSysMessage("TRANSMOG_SYNC:%u", itemId);
        }
        handler->SendSysMessage(LANG_CMD_TRANSMOG_COMPLETE_SYNC);
        return true;
    }

    static bool HandleDisableTransMogVisual(ChatHandler* handler, bool hide)
    {
        Player* player = handler->GetPlayer();

        if (hide)
        {
            player->UpdatePlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG, 0);
            handler->SendSysMessage(LANG_CMD_TRANSMOG_SHOW);
        }
        else
        {
            player->UpdatePlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG, 1);
            handler->SendSysMessage(LANG_CMD_TRANSMOG_HIDE);
        }

        player->UpdateObjectVisibility();
        return true;
    }

    static bool HandleAddTransmogItem(ChatHandler* handler, Optional<PlayerIdentifier> player, ItemTemplate const* itemTemplate)
    {
        if (!sTransmogrification->GetUseCollectionSystem())
            return true;

        if (!sObjectMgr->GetItemTemplate(itemTemplate->ItemId))
        {
            handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemTemplate->ItemId);
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (!player)
        {
            player = PlayerIdentifier::FromTargetOrSelf(handler);
        }

        if (!player)
        {
            return false;
        }

        Player* target = player->GetConnectedPlayer();
        bool isNotConsole = handler->GetSession();
        bool suitableForTransmog;

        if (target)
        {
            suitableForTransmog = sTransmogrification->SuitableForTransmogrification(target, itemTemplate);
        }
        else
        {
            suitableForTransmog = sTransmogrification->SuitableForTransmogrification(player->GetGUID(), itemTemplate);
        }

        if (!sTransmogrification->GetTrackUnusableItems() && !suitableForTransmog)
        {
            handler->SendSysMessage(LANG_CMD_TRANSMOG_ADD_UNSUITABLE);
            handler->SetSentErrorMessage(true);
            return true;
        }

        if (itemTemplate->Class != ITEM_CLASS_ARMOR && itemTemplate->Class != ITEM_CLASS_WEAPON)
        {
            handler->SendSysMessage(LANG_CMD_TRANSMOG_ADD_FORBIDDEN);
            handler->SetSentErrorMessage(true);
            return true;
        }

        auto guid = player->GetGUID();
        uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid);
        uint32 itemId = itemTemplate->ItemId;

        std::stringstream tempStream;
        tempStream << std::hex << ItemQualityColors[itemTemplate->Quality];
        std::string itemQuality = tempStream.str();
        std::string itemName = itemTemplate->Name1;
        std::string playerName = player->GetName();
        std::string nameLink = handler->playerLink(playerName);

        if (sTransmogrification->AddCollectedAppearance(accountId, itemId))
        {
            // Notify target of new item in appearance collection
            if (target && !(target->GetPlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG).value) && !sTransmogrification->CanNeverTransmog(itemTemplate))
            {
                ChatHandler(target->GetSession()).PSendSysMessage(R"(|c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r has been added to your appearance collection.)", itemQuality.c_str(), itemId, itemName.c_str());
            }

            // Feedback of successful command execution to GM
            if (isNotConsole && target != handler->GetPlayer())
            {
                handler->PSendSysMessage(R"(|c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r has been added to the appearance collection of Player %s.)", itemQuality.c_str(), itemId, itemName.c_str(), nameLink);
            }

            CharacterDatabase.Execute("INSERT INTO custom_unlocked_appearances (account_id, item_template_id) VALUES ({}, {})", accountId, itemId);
        }
        else
        {
            // Feedback of failed command execution to GM
            if (isNotConsole)
            {
                handler->PSendSysMessage(R"(Player %s already has item |c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r in the appearance collection.)", nameLink, itemQuality.c_str(), itemId, itemName.c_str());
                handler->SetSentErrorMessage(true);
            }
        }

        return true;
    }

    static bool HandleAddTransmogItemSet(ChatHandler* handler, Optional<PlayerIdentifier> player, Variant<Hyperlink<itemset>, uint32> itemSetId)
    {
        if (!sTransmogrification->GetUseCollectionSystem())
            return true;

        if (!*itemSetId)
        {
            handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, uint32(itemSetId));
            handler->SetSentErrorMessage(true);
            return false;
        }

        if (!player)
        {
            player = PlayerIdentifier::FromTargetOrSelf(handler);
        }

        if (!player)
        {
            return false;
        }

        Player* target = player->GetConnectedPlayer();
        ItemSetEntry const* set = sItemSetStore.LookupEntry(uint32(itemSetId));
        bool isNotConsole = handler->GetSession();

        if (!set)
        {
            handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, uint32(itemSetId));
            handler->SetSentErrorMessage(true);
            return false;
        }

        auto guid = player->GetGUID();
        CharacterCacheEntry const* playerData = sCharacterCache->GetCharacterCacheByGuid(guid);
        if (!playerData)
            return false;

        bool added = false;
        uint32 error = 0;
        uint32 itemId;
        uint32 accountId = playerData->AccountId;

        for (uint32 i = 0; i < MAX_ITEM_SET_ITEMS; ++i)
        {
            itemId = set->itemId[i];
            if (itemId)
            {
                ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
                if (itemTemplate)
                {
                    if (!sTransmogrification->GetTrackUnusableItems() && (
                            (target && !sTransmogrification->SuitableForTransmogrification(target, itemTemplate)) ||
                            !sTransmogrification->SuitableForTransmogrification(guid, itemTemplate)
                            ))
                    {
                        error = LANG_CMD_TRANSMOG_ADD_UNSUITABLE;
                        continue;
                    }
                    if (itemTemplate->Class != ITEM_CLASS_ARMOR && itemTemplate->Class != ITEM_CLASS_WEAPON)
                    {
                        error = LANG_CMD_TRANSMOG_ADD_FORBIDDEN;
                        continue;
                    }

                    if (sTransmogrification->AddCollectedAppearance(accountId, itemId))
                    {
                        CharacterDatabase.Execute("INSERT INTO custom_unlocked_appearances (account_id, item_template_id) VALUES ({}, {})", accountId, itemId);
                        added = true;
                    }
                }
            }
        }

        if (!added && error > 0)
        {
            handler->SendSysMessage(error);
            handler->SetSentErrorMessage(true);
            return true;
        }

        int locale = handler->GetSessionDbcLocale();
        std::string setName = set->name[locale];
        std::string nameLink = handler->playerLink(player->GetName());

        // Feedback of command execution to GM
        if (isNotConsole)
        {
            // Failed command execution
            if (!added)
            {
                handler->PSendSysMessage("Player %s already has ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r in the appearance collection.", nameLink, uint32(itemSetId), setName.c_str(), localeNames[locale]);
                handler->SetSentErrorMessage(true);
                return true;
            }

            // Successful command execution
            if (target != handler->GetPlayer())
            {
                handler->PSendSysMessage("ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r has been added to the appearance collection of Player %s.", uint32(itemSetId), setName.c_str(), localeNames[locale], nameLink);
            }
        }

        // Notify target of new item in appearance collection
        if (target && !(target->GetPlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG).value))
        {
            ChatHandler(target->GetSession()).PSendSysMessage("ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r has been added to your appearance collection.", uint32(itemSetId), setName.c_str(), localeNames[locale]);
        }

        return true;
    }
};

void AddSC_transmog_commandscript()
{
    new transmog_commandscript();
}
<|endoftext|>