File indexing completed on 2024-09-22 04:08:42

0001 /*
0002  *  SPDX-FileCopyrightText: 2022 Deif Lou <ginoba@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISSPRAYRANDOMDISTRIBUTIONS_H
0008 #define KISSPRAYRANDOMDISTRIBUTIONS_H
0009 
0010 #include <QScopedPointer>
0011 
0012 #include <kis_random_source.h>
0013 #include <kis_cubic_curve.h>
0014 
0015 /**
0016  * @brief Class that can generate randomly distributed values in the range
0017  *        [a..b] following an arbitrary pdf
0018  */
0019 class KisSprayFunctionBasedDistribution
0020 {
0021 public:
0022     /**
0023      * @brief Construct an invalid KisSprayFunctionBasedDistribution
0024      */
0025     KisSprayFunctionBasedDistribution();
0026 
0027     /**
0028      * @brief Construct a new distribution
0029      * @tparam Function Type of the functor to sample from
0030      * @param numberOfSamples Number of points to sample from the function. They
0031      *                        are sampled evenly through the range [a..b].
0032      *                        The first point will be sampled at @p a and the
0033      *                        last one at @p b.
0034      * @param a The lower bound of the domain of the function. The sampling will
0035      *          start here
0036      * @param b The upper bound of the domain of the function. The sampling will
0037      *          start here
0038      * @param f The functor that will be used to get the samples
0039      */
0040     template <typename Function>
0041     KisSprayFunctionBasedDistribution(int numberOfSamples, double a, double b, Function f);
0042 
0043     ~KisSprayFunctionBasedDistribution();
0044     KisSprayFunctionBasedDistribution(const KisSprayFunctionBasedDistribution &other);
0045     KisSprayFunctionBasedDistribution& operator=(const KisSprayFunctionBasedDistribution &rhs);
0046 
0047     /**
0048      * @brief Get a random value between @ref min and @ref max that follows the distribution
0049      * @param rs The random source object that will be used to get a uniform value
0050      * @return A random value between @ref min and @ref max that follows the
0051      *         distribution
0052      */
0053     double operator()(KisRandomSourceSP rs) const;
0054 
0055     /**
0056      * @brief Return the minimum value that this distribution can produce
0057      */
0058     double min() const;
0059 
0060     /**
0061      * @brief Return the maximum value that this distribution can produce
0062      */
0063     double max() const;
0064 
0065     /**
0066      * @brief Return if this object is correctly initialized and can be used to
0067      *        generate values
0068      */
0069     bool isValid() const;
0070 
0071 protected:
0072     /**
0073      * @brief Function used to setup the distribution and put it in a valid
0074      *        state. See the constructor for the explanation of the parameters
0075      */
0076     template <typename Function>
0077     void initialize(size_t numberOfSamples, double a, double b, Function f);
0078 
0079 private:
0080     class Private;
0081     QScopedPointer<Private> m_d;
0082 };
0083 
0084 /**
0085  * @brief Class that can generate uniformly distributed values in
0086  *        the [0..1) range
0087  */
0088 class KisSprayUniformDistribution
0089 {
0090 public:
0091     /**
0092      * @brief Get a random value between @ref min and @ref max that follows a uniform distribution
0093      * @param rs The random source object that will be used to get a uniform value
0094      * @return A random value between @ref min and @ref max that follows the
0095      *         distribution
0096      */
0097     double operator()(KisRandomSourceSP rs) const;
0098 
0099     /**
0100      * @brief Return the minimum value that this distribution can produce
0101      */
0102     double min() const { return 0.0; }
0103 
0104     /**
0105      * @brief Return the maximum value that this distribution can produce
0106      */
0107     double max() const { return 1.0; }
0108 
0109     /**
0110      * @brief Return if this object is correctly initialized and can be used to
0111      *        generate values
0112      */
0113     bool isValid() const { return true; }
0114 };
0115 
0116 /**
0117  * @brief Class that can generate uniformly distributed values in
0118  *        the [0..1) range, for polar coordinates distance
0119  */
0120 class KisSprayUniformDistributionPolarDistance : public KisSprayUniformDistribution
0121 {
0122 public:
0123     double operator()(KisRandomSourceSP rs) const;
0124 };
0125 
0126 /**
0127  * @brief Class that can generate normally distributed values. For efficiency,
0128  *        the values will be in the range [0..standardDeviation*5]
0129  */
0130 class KisSprayNormalDistribution : public KisSprayFunctionBasedDistribution
0131 {
0132 public:
0133     /**
0134      * @brief Construct an invalid KisSprayNormalDistribution
0135      */
0136     KisSprayNormalDistribution();
0137 
0138     /**
0139      * @brief Construct a new normal distribution
0140      * @param mean Where the "peak" of the distribution should lie or how much
0141      *             the distribution is shifted left or right
0142      * @param standardDeviation How spread should the distribution be
0143      */
0144     KisSprayNormalDistribution(double mean, double standardDeviation);
0145 };
0146 
0147 /**
0148  * @brief Class that can generate normally distributed values. For efficiency,
0149  *        the values will be in the range [0..standardDeviation*5], for polar
0150  *        coordinates distance
0151  * @see KisSprayNormalDistribution
0152  */
0153 class KisSprayNormalDistributionPolarDistance : public KisSprayNormalDistribution
0154 {
0155 public:
0156     KisSprayNormalDistributionPolarDistance();
0157     KisSprayNormalDistributionPolarDistance(double mean, double standardDeviation);
0158 };
0159 
0160 /**
0161  * @brief Class that can generate randomly distributed values in the range
0162  *        [0..1] that follow a distribution that clusters the values
0163  *        towards 0 or 1
0164  */
0165 class KisSprayClusterBasedDistribution : public KisSprayFunctionBasedDistribution
0166 {
0167 public:
0168     /**
0169      * @brief Construct an invalid KisSprayClusterBasedDistribution
0170      */
0171     KisSprayClusterBasedDistribution();
0172 
0173     /**
0174      * @brief Construct a new cluster based distribution
0175      * @param clusteringAmount A value in the range [-100..100] that indicates
0176      *                         how and how much the generated values should
0177      *                         cluster. A positive clustering amount will make
0178      *                         generated values cluster towards 0 whereas a
0179      *                         negative amount will cluster them towards 1. The
0180      *                         bigger the clustering amount, the more pronounced
0181      *                         will be the clustering, and the smaller it is,
0182      *                         the more evenly distributed the values will be
0183      */
0184     explicit KisSprayClusterBasedDistribution(double clusteringAmount);
0185 };
0186 
0187 /**
0188  * @brief Class that can generate randomly distributed values in the range
0189  *        [0..1] that follow a distribution that clusters the values
0190  *        towards 0 or 1, for polar coordinates distance
0191  * @see KisSprayClusterBasedDistribution
0192  */
0193 class KisSprayClusterBasedDistributionPolarDistance : public KisSprayFunctionBasedDistribution
0194 {
0195 public:
0196     KisSprayClusterBasedDistributionPolarDistance();
0197     explicit KisSprayClusterBasedDistributionPolarDistance(double clusteringAmount);
0198 };
0199 
0200 /**
0201  * @brief Class that can generate randomly distributed values in the range
0202  *        [0..1] that follow a distribution given by a user defined cubic curve
0203  */
0204 class KisSprayCurveBasedDistribution : public KisSprayFunctionBasedDistribution
0205 {
0206 public:
0207     /**
0208      * @brief Construct an invalid KisSprayCurveBasedDistribution
0209      */
0210     KisSprayCurveBasedDistribution();
0211 
0212     /**
0213      * @brief Construct a new curve based distribution
0214      * @param curve A cubic curve that will be used as pdf
0215      * @param repeat The number of times the given curve should repeat in the
0216      *               range [0..1] 
0217      */
0218     explicit KisSprayCurveBasedDistribution(const KisCubicCurve &curve, size_t repeat = 1);
0219 };
0220 
0221 /**
0222  * @brief Class that can generate randomly distributed values in the range
0223  *        [0..1] that follow a distribution given by a user defined cubic curve,
0224  *        for polar coordinates distance
0225  * @see KisSprayCurveBasedDistribution
0226  */
0227 class KisSprayCurveBasedDistributionPolarDistance : public KisSprayFunctionBasedDistribution
0228 {
0229 public:
0230     KisSprayCurveBasedDistributionPolarDistance();
0231     explicit KisSprayCurveBasedDistributionPolarDistance(const KisCubicCurve &curve, size_t repeat = 1);
0232 };
0233 
0234 #endif