001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 * image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause).
006 * Copyright (c) 2006-2023 Wilhelm Burger, Mark J. Burge. All rights reserved.
007 * Visit https://imagingbook.com for additional details.
008 ******************************************************************************/
009
010package imagingbook.common.noise.perlin;
011
012import imagingbook.common.noise.hashing.Hash32Shift;
013import imagingbook.common.noise.hashing.HashFunction;
014
015/**
016 * <p>
017 * Gradient (Perlin) noise implementation (see [1] for a detailed description). This is the super-class for all other
018 * Perlin noise generators (1D, 2D, N-dimensional).
019 * </p>
020 * <p>
021 * [1] W. Burger, M.J. Burge, <em>Principles of Digital Image Processing &ndash; Advanced Methods</em> (Vol. 3),
022 * Supplementary Chapter 8: "Synthetic Gradient Noise", Springer (2013). <a href=
023 * "https://dx.doi.org/10.13140/RG.2.1.3427.7284">https://dx.doi.org/10.13140/RG.2.1.3427.7284</a>
024 * </p>
025 *
026 * @author WB
027 * @version 2022/11/24
028 */
029public abstract class PerlinNoiseGenerator {
030
031        private final double f_min;
032        private final double f_max;
033        private final int oct;
034        private final double persistence; // persistence (phi)
035        
036        final double[] F;               // frequencies f_i
037        final double[] A;               // amplitudes a_i
038        final HashFunction hashFun;
039
040        /**
041         * Constructor (non-public).
042         */
043        PerlinNoiseGenerator(double f_min, double f_max, double persistence, HashFunction hash) {
044                if (f_max < f_min) {
045                        throw new IllegalArgumentException("f_max must not be less than f_min");
046                }
047                this.f_min = f_min;
048                this.f_max = f_max;
049                this.oct = getFrequencySteps(f_min, f_max);
050                this.F = new double[oct];
051                this.A = new double[oct];
052                this.persistence = persistence;
053                this.hashFun = (hash != null) ? hash : new Hash32Shift();       // default
054                this.makeFrequencies(f_min, f_max);
055        }
056
057        /**
058         * Perlin's improved "fading" function s(x)
059         *
060         * @param x interpolation position in [0,1]
061         * @return s(x) = 10 x^3 - 15 x^4 + 6 x^5
062         */
063        double s(double x) {
064                return x * x * x * (x * (x * 6 - 15) + 10);
065        }
066
067        // ----------------- helper methods: ----------------------------
068        
069        private void makeFrequencies(double fmin, double fmax) {
070                int n = 0;
071                double f = f_min;
072                double a = 1;
073                while (f <= f_max && n < oct) {
074                        F[n] = f;
075                        A[n] = a;
076                        n = n + 1;
077                        f = 2 * f;
078                        a = persistence * a;
079                }
080        }
081
082        private int getFrequencySteps(double fmin, double fmax) {       // TODO: should not be public!
083                int i = 0;
084                double f = fmin;
085                while (f <= fmax) {
086                        i = i + 1;
087                        f = 2 * f;
088                }
089                return i;
090        }
091        
092        /**
093         * Fast floor method (by Gustavson?)
094         * @param x argument
095         * @return floor(x), works for pos. and neg. x.
096         */
097        int ffloor(double x) {
098                int xint = (int) x;
099                return (xint < x) ? xint : xint - 1;
100        }
101
102        // -----------------------------------------------
103
104        /**
105         * Returns an array with the frequencies f_i used for generating the noise function
106         * @return an array of frequencies
107         */
108        public double[] getFrequencies() {
109                return F;
110        }
111
112        /**
113         * Returns an array with the amplitudes a_i used for generating * the noise function.
114         *
115         * @return an array of amplitudes
116         */
117        public double[] getAmplitudes() {
118                return A;
119        }
120
121}