001/* 002Copyright 2006 Jerry Huxtable 003 004Licensed under the Apache License, Version 2.0 (the "License"); 005you may not use this file except in compliance with the License. 006You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010Unless required by applicable law or agreed to in writing, software 011distributed under the License is distributed on an "AS IS" BASIS, 012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013See the License for the specific language governing permissions and 014limitations under the License. 015*/ 016 017package com.jhlabs.image; 018 019import java.awt.*; 020import java.awt.geom.*; 021import java.awt.image.*; 022 023/** 024 * A Filter which produces the effect of looking into a kaleidoscope. 025 */ 026public class KaleidoscopeFilter extends TransformFilter { 027 028 private float angle = 0; 029 private float angle2 = 0; 030 private float centreX = 0.5f; 031 private float centreY = 0.5f; 032 private int sides = 3; 033 private float radius = 0; 034 035 private float icentreX; 036 private float icentreY; 037 038 /** 039 * Construct a KaleidoscopeFilter with no distortion. 040 */ 041 public KaleidoscopeFilter() { 042 setEdgeAction( CLAMP ); 043 } 044 045 /** 046 * Set the number of sides of the kaleidoscope. 047 * @param sides the number of sides 048 * @min-value 2 049 * @see #getSides 050 */ 051 public void setSides(int sides) { 052 this.sides = sides; 053 } 054 055 /** 056 * Get the number of sides of the kaleidoscope. 057 * @return the number of sides 058 * @see #setSides 059 */ 060 public int getSides() { 061 return sides; 062 } 063 064 /** 065 * Set the angle of the kaleidoscope. 066 * @param angle the angle of the kaleidoscope. 067 * @angle 068 * @see #getAngle 069 */ 070 public void setAngle(float angle) { 071 this.angle = angle; 072 } 073 074 /** 075 * Get the angle of the kaleidoscope. 076 * @return the angle of the kaleidoscope. 077 * @see #setAngle 078 */ 079 public float getAngle() { 080 return angle; 081 } 082 083 /** 084 * Set the secondary angle of the kaleidoscope. 085 * @param angle2 the angle 086 * @angle 087 * @see #getAngle2 088 */ 089 public void setAngle2(float angle2) { 090 this.angle2 = angle2; 091 } 092 093 /** 094 * Get the secondary angle of the kaleidoscope. 095 * @return the angle 096 * @see #setAngle2 097 */ 098 public float getAngle2() { 099 return angle2; 100 } 101 102 /** 103 * Set the centre of the effect in the X direction as a proportion of the image size. 104 * @param centreX the center 105 * @see #getCentreX 106 */ 107 public void setCentreX( float centreX ) { 108 this.centreX = centreX; 109 } 110 111 /** 112 * Get the centre of the effect in the X direction as a proportion of the image size. 113 * @return the center 114 * @see #setCentreX 115 */ 116 public float getCentreX() { 117 return centreX; 118 } 119 120 /** 121 * Set the centre of the effect in the Y direction as a proportion of the image size. 122 * @param centreY the center 123 * @see #getCentreY 124 */ 125 public void setCentreY( float centreY ) { 126 this.centreY = centreY; 127 } 128 129 /** 130 * Get the centre of the effect in the Y direction as a proportion of the image size. 131 * @return the center 132 * @see #setCentreY 133 */ 134 public float getCentreY() { 135 return centreY; 136 } 137 138 /** 139 * Set the centre of the effect as a proportion of the image size. 140 * @param centre the center 141 * @see #getCentre 142 */ 143 public void setCentre( Point2D centre ) { 144 this.centreX = (float)centre.getX(); 145 this.centreY = (float)centre.getY(); 146 } 147 148 /** 149 * Get the centre of the effect as a proportion of the image size. 150 * @return the center 151 * @see #setCentre 152 */ 153 public Point2D getCentre() { 154 return new Point2D.Float( centreX, centreY ); 155 } 156 157 /** 158 * Set the radius of the effect. 159 * @param radius the radius 160 * @min-value 0 161 * @see #getRadius 162 */ 163 public void setRadius( float radius ) { 164 this.radius = radius; 165 } 166 167 /** 168 * Get the radius of the effect. 169 * @return the radius 170 * @see #setRadius 171 */ 172 public float getRadius() { 173 return radius; 174 } 175 176 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 177 icentreX = src.getWidth() * centreX; 178 icentreY = src.getHeight() * centreY; 179 return super.filter( src, dst ); 180 } 181 182 protected void transformInverse(int x, int y, float[] out) { 183 double dx = x-icentreX; 184 double dy = y-icentreY; 185 double r = Math.sqrt( dx*dx + dy*dy ); 186 double theta = Math.atan2( dy, dx ) - angle - angle2; 187 theta = ImageMath.triangle( (float)( theta/Math.PI*sides*.5 ) ); 188 if ( radius != 0 ) { 189 double c = Math.cos(theta); 190 double radiusc = radius/c; 191 r = radiusc * ImageMath.triangle( (float)(r/radiusc) ); 192 } 193 theta += angle; 194 195 out[0] = (float)(icentreX + r*Math.cos(theta)); 196 out[1] = (float)(icentreY + r*Math.sin(theta)); 197 } 198 199 public String toString() { 200 return "Distort/Kaleidoscope..."; 201 } 202 203}