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.hashing;
011
012/**
013 * <p>
014 * Permutation-based hash function, similar to the one proposed in [1]. See [2] for details.
015 * </p>
016 * <p>
017 * [1] K. Perlin. An image synthesizer. SIGGRAPH Computer Graphics 19(3), 287–296 (1985). <br> [2] W. Burger, M.J.
018 * Burge, <em>Principles of Digital Image Processing &ndash; Advanced Methods</em> (Vol. 3), Supplementary Chapter 8:
019 * "Synthetic Gradient Noise", Springer (2013). <a href=
020 * "https://dx.doi.org/10.13140/RG.2.1.3427.7284">https://dx.doi.org/10.13140/RG.2.1.3427.7284</a>
021 * </p>
022 *
023 * @author WB
024 * @version 2022/11/24
025 */
026public class HashPermute implements HashFunction {
027        
028        private final int seed;
029        
030        /**
031         * Constructor, creates a hash function with a random seed value.
032         */
033        HashPermute() {
034                this(0);
035        }
036        
037        /**
038         * Constructor creating a hash function with the specified seed value.
039         * @param seed the random seed value (set to 0 use a random seed value).
040         */
041        public HashPermute(int seed) {
042                this.seed = HashFunction.getRandomSeed(seed);
043        }
044        
045        @Override
046        public double hash(int u) {
047                int h = h8(u);
048                return (double) (h & 0xFF) / 0xFF; // use bits 0..7 for d
049        }
050        
051        // 6 bits per channel (overlapping blocks)
052        @Override
053        public double[] hash(int u, int v) {
054                final int M = 0x3F; // 63;
055                int h = h8(u, v);
056                double hx = h & M;                      // use bits 0..5 for dx
057                double hy = (h >> 2) & M;       // use bits 2..7 for dy
058                return new double[] {hx/M, hy/M};
059        }
060        
061        @Override
062        public double[] hash(int u, int v, int w) {
063                final int M = 0x0F;
064                int h = h8(u, v, w);
065                double hx =  h & M;                     // use bits 0..3 for x
066                double hy = ((h >> 2) & M);     // use bits 2..5 for y
067                double hz = ((h >> 4) & M);     // use bits 4..7 for z
068                return new double[] {hx/M, hy/M, hz/M};
069        }
070
071        // 2 dimensions
072        private int h8 (int u) {
073                u = (u + seed) & 0xFF;
074                return P[u];
075        }
076        
077        // 2 dimensions
078        private int h8 (int u, int v) {
079                u = (u + seed) & 0xFF;
080                v = v & 0xFF;
081                return P[P[v] + u];
082        }
083        
084        // 3 dimensions
085        private int h8 (int u, int v, int w) {
086                u = (u + seed) & 0xFF;
087                v = v & 0xFF;
088                w = w & 0xFF;
089                return P[P[P[w] + v] + u];
090        }
091
092
093        /**
094         * N-dimensional permutation hash; this version does not use any bit splitting. Instead, the hash8() function is
095         * applied repeatedly for every gradient dimension by using the dimension number (k) as a local seed (sd) - in
096         * addition to the global seed (seed).
097         */
098        @Override
099        public double[] hash(int[] p) {
100                int N = p.length;
101                double[] g = new double[N];
102                for (int k = 0; k < N; k++) {           // dimension k
103                        int h = h8(p, k + seed);
104                        g[k] = (double) (h & 0xFF) / 0xFF;
105                }
106                return g;
107        }
108        
109        /*
110         * N-dimensional permutation hash function
111         */
112        private int h8 (int[] p, int sd) {
113                int h = sd & 0xFF;
114                for (int k = 0; k < p.length; k++) {
115                        h = P[h + p[k] & 0xFF];
116                }
117                return h;
118        }
119
120        /**
121         * Permutation table P[i], for i = 0..255. To avoid index wrapping, table's length is doubled to 512.
122         */
123        static final int P[] = new int[512];
124        static {
125                int[] perm = {
126                                151, 160, 137, 91, 90, 15, 131, 13, 
127                                201, 95, 96, 53, 194, 233, 7, 225, 
128                                140, 36, 103, 30, 69, 142, 8, 99, 
129                                37, 240, 21, 10, 23, 190, 6, 148, 
130                                247, 120, 234, 75, 0, 26, 197, 62,
131                                94,     252, 219, 203, 117, 35, 11, 32, 
132                                57, 177, 33, 88, 237, 149, 56, 87, 
133                                174, 20, 125, 136, 171, 168, 68, 175, 
134                                74, 165, 71, 134, 139, 48, 27, 166, 
135                                77, 146, 158, 231, 83, 111, 229, 122, 
136                                60, 211, 133, 230, 220, 105, 92, 41, 
137                                55, 46, 245, 40, 244, 102, 143, 54, 
138                                65, 25, 63, 161, 1, 216, 80, 73, 
139                                209, 76, 132, 187, 208, 89, 18, 169, 
140                                200, 196, 135, 130, 116, 188, 159, 86, 
141                                164, 100, 109, 198, 173, 186, 3, 64,
142                                52, 217, 226, 250, 124, 123, 5, 202, 
143                                38, 147, 118, 126, 255, 82, 85, 212, 
144                                207, 206, 59, 227, 47, 16, 58, 17, 
145                                182, 189, 28, 42, 223, 183, 170, 213, 
146                                119, 248, 152, 2, 44, 154, 163, 70, 
147                                221, 153, 101, 155, 167, 43, 172, 9,
148                                129, 22, 39, 253, 19, 98, 108, 110, 
149                                79, 113, 224, 232, 178, 185, 112, 104,
150                                218, 246, 97, 228, 251, 34, 242, 193, 
151                                238, 210, 144, 12, 191, 179, 162, 241, 
152                                81, 51, 145, 235, 249, 14, 239, 107, 
153                                49, 192, 214, 31, 181, 199, 106, 157, 
154                                184, 84, 204, 176, 115, 121, 50, 45, 
155                                127, 4, 150, 254, 138, 236, 205, 93, 
156                                222, 114, 67, 29, 24, 72, 243, 141, 
157                                128, 195, 78, 66, 215, 61, 156, 180 };
158                for (int i = 0; i < 256; i++)
159                        P[256 + i] = P[i] = perm[i];
160        }
161
162}