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-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.pub.noise.perlin;
011
012import imagingbook.pub.noise.hashing.HashFun;
013
014/**
015 * Gradient (Perlin) noise implementation. 
016 * This class implements a 2D Perlin noise generator.
017 */
018
019public class PerlinNoiseGen2d extends PerlinNoiseGen {
020        
021        public PerlinNoiseGen2d(double f_min, double f_max, double persistence, HashFun hf) {
022                super(f_min, f_max, persistence, hf);
023        }
024        
025        /**
026         * 2D combined (multi-frequency) Perlin noise function. 
027         * @param x Interpolation position x.
028         * @param y Interpolation position y.
029         * @return The value of the combined Perlin
030         * noise function for the two-dimensional position (x,y).
031         */
032        public double NOISE(double x, double y) {
033                double sum = 0;
034                for (int i=0; i<F.length; i++) {
035                        sum = sum + A[i] * noise(F[i] * x, F[i] * y);
036                }
037                return sum;
038        }
039        
040        /**
041         * 2D elementary (single-frequency) Perlin noise function. 
042         * @param x Interpolation position x.
043         * @param y Interpolation position y.
044         * @return The value of the elementary Perlin
045         * noise function for the two-dimensional position (x,y).
046         */
047        public double noise(double x, double y) {
048                int px = (int) ffloor(x);
049                int py = (int) ffloor(y);
050                double[] g00 = gradient(px, py);
051                double[] g10 = gradient(px+1, py);
052                double[] g01 = gradient(px, py+1);
053                double[] g11 = gradient(px+1, py+1);
054                double x01 = x-px;      // x01 is in [0,1]
055                double y01 = y-py;      // y01 is in [0,1]
056                double w00 = g00[0]*(x01)   + g00[1]*(y01);
057                double w10 = g10[0]*(x01-1) + g10[1]*(y01);
058                double w01 = g01[0]*(x01)   + g01[1]*(y01-1);
059                double w11 = g11[0]*(x01-1) + g11[1]*(y01-1);
060                return interpolate(x01, y01, w00, w10, w01, w11);
061        }
062        
063        /**
064         * @param px discrete horiz. position
065         * @param py discrete vert. position
066         * @return A pseudo-random gradient vector for the discrete position (px,py).
067         */
068        double[] gradient(int px, int py) {
069                double[] g = hashFun.hash(px,py);       // hash() always returns a new double[] in [0,1]
070                g[0] = 2.0 * g[0] - 1;
071                g[1] = 2.0 * g[1] - 1;
072                return g;
073        }
074
075        /**
076         * Local interpolation function.
077         * @param x01 Horizontal interpolation position in [0,1]
078         * @param y01 Vertical interpolation position in [0,1]
079         * @param w00 Tangent value for position (0,0).
080         * @param w01 Tangent value for position (1,0).
081         * @param w10 Tangent value for position (0,1).
082         * @param w11 Tangent value for position (1,1).
083         * @return  The interpolated noise value at position (x01,y01).
084         */
085        double interpolate(double x01, double y01, double w00, double w10, double w01, double w11) { 
086                double sx = this.s(x01); 
087                double w0 = (1 - sx) * w00 + sx * w10;
088                double w1 = (1 - sx) * w01 + sx * w11;
089                double sy = this.s(y01);
090                double w = (1 - sy) * w0 + sy * w1;
091                return w;
092        }       
093
094}