001 /* 002 * 003 004 Licensed under the Apache License, Version 2.0 (the "License"); 005 you may not use this file except in compliance with the License. 006 You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010 Unless required by applicable law or agreed to in writing, software 011 distributed under the License is distributed on an "AS IS" BASIS, 012 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 See the License for the specific language governing permissions and 014 limitations under the License. 015 */ 016 017 package railo.runtime.img.math; 018 019 import java.util.Random; 020 021 public class CellularFunction2D implements Function2D { 022 023 public float distancePower = 2; 024 public boolean cells = false; 025 public boolean angular = false; 026 private float[] coefficients = { 1, 0, 0, 0 }; 027 private Random random = new Random(); 028 private Point[] results = null; 029 030 public CellularFunction2D() { 031 results = new Point[2]; 032 for (int j = 0; j < results.length; j++) 033 results[j] = new Point(); 034 } 035 036 public void setCoefficient(int c, float v) { 037 coefficients[c] = v; 038 } 039 040 public float getCoefficient(int c) { 041 return coefficients[c]; 042 } 043 044 class Point { 045 int index; 046 float x, y; 047 float distance; 048 } 049 050 private float checkCube(float x, float y, int cubeX, int cubeY, Point[] results) { 051 random.setSeed(571*cubeX + 23*cubeY); 052 int numPoints = 3 + random.nextInt() % 4; 053 numPoints = 4; 054 055 for (int i = 0; i < numPoints; i++) { 056 float px = random.nextFloat(); 057 float py = random.nextFloat(); 058 float dx = Math.abs(x-px); 059 float dy = Math.abs(y-py); 060 float d; 061 if (distancePower == 1.0f) 062 d = dx + dy; 063 else if (distancePower == 2.0f) 064 d = (float)Math.sqrt(dx*dx + dy*dy); 065 else 066 d = (float)Math.pow(Math.pow(dx, distancePower) + Math.pow(dy, distancePower), 1/distancePower); 067 068 // Insertion sort 069 for (int j = 0; j < results.length; j++) { 070 if (results[j].distance == Double.POSITIVE_INFINITY) { 071 Point last = results[j]; 072 last.distance = d; 073 last.x = px; 074 last.y = py; 075 results[j] = last; 076 break; 077 } else if (d < results[j].distance) { 078 Point last = results[results.length-1]; 079 for (int k = results.length-1; k > j; k--) 080 results[k] = results[k-1]; 081 last.distance = d; 082 last.x = px; 083 last.y = py; 084 results[j] = last; 085 break; 086 } 087 } 088 } 089 return results[1].distance; 090 } 091 092 public float evaluate(float x, float y) { 093 for (int j = 0; j < results.length; j++) 094 results[j].distance = Float.POSITIVE_INFINITY; 095 096 int ix = (int)x; 097 int iy = (int)y; 098 float fx = x-ix; 099 float fy = y-iy; 100 101 float d = checkCube(fx, fy, ix, iy, results); 102 if (d > fy) 103 d = checkCube(fx, fy+1, ix, iy-1, results); 104 if (d > 1-fy) 105 d = checkCube(fx, fy-1, ix, iy+1, results); 106 if (d > fx) { 107 checkCube(fx+1, fy, ix-1, iy, results); 108 if (d > fy) 109 d = checkCube(fx+1, fy+1, ix-1, iy-1, results); 110 if (d > 1-fy) 111 d = checkCube(fx+1, fy-1, ix-1, iy+1, results); 112 } 113 if (d > 1-fx) { 114 d = checkCube(fx-1, fy, ix+1, iy, results); 115 if (d > fy) 116 d = checkCube(fx-1, fy+1, ix+1, iy-1, results); 117 if (d > 1-fy) 118 d = checkCube(fx-1, fy-1, ix+1, iy+1, results); 119 } 120 121 float t = 0; 122 for (int i = 0; i < 2; i++) 123 t += coefficients[i] * results[i].distance; 124 if (angular) 125 t += Math.atan2(fy-results[0].y, fx-results[0].x) / (2*Math.PI) + 0.5; 126 return t; 127 } 128 129 }