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 simulates a lens placed over an image. 025 */ 026public class SphereFilter extends TransformFilter { 027 028 private float a = 0; 029 private float b = 0; 030 private float a2 = 0; 031 private float b2 = 0; 032 private float centreX = 0.5f; 033 private float centreY = 0.5f; 034 private float refractionIndex = 1.5f; 035 036 private float icentreX; 037 private float icentreY; 038 039 public SphereFilter() { 040 setEdgeAction( CLAMP ); 041 setRadius( 100.0f ); 042 } 043 044 /** 045 * Set the index of refaction. 046 * @param refractionIndex the index of refaction 047 * @see #getRefractionIndex 048 */ 049 public void setRefractionIndex(float refractionIndex) { 050 this.refractionIndex = refractionIndex; 051 } 052 053 /** 054 * Get the index of refaction. 055 * @return the index of refaction 056 * @see #setRefractionIndex 057 */ 058 public float getRefractionIndex() { 059 return refractionIndex; 060 } 061 062 /** 063 * Set the radius of the effect. 064 * @param r the radius 065 * @min-value 0 066 * @see #getRadius 067 */ 068 public void setRadius(float r) { 069 this.a = r; 070 this.b = r; 071 } 072 073 /** 074 * Get the radius of the effect. 075 * @return the radius 076 * @see #setRadius 077 */ 078 public float getRadius() { 079 return a; 080 } 081 082 /** 083 * Set the centre of the effect in the X direction as a proportion of the image size. 084 * @param centreX the center 085 * @see #getCentreX 086 */ 087 public void setCentreX( float centreX ) { 088 this.centreX = centreX; 089 } 090 091 public float getCentreX() { 092 return centreX; 093 } 094 095 /** 096 * Set the centre of the effect in the Y direction as a proportion of the image size. 097 * @param centreY the center 098 * @see #getCentreY 099 */ 100 public void setCentreY( float centreY ) { 101 this.centreY = centreY; 102 } 103 104 /** 105 * Get the centre of the effect in the Y direction as a proportion of the image size. 106 * @return the center 107 * @see #setCentreY 108 */ 109 public float getCentreY() { 110 return centreY; 111 } 112 113 /** 114 * Set the centre of the effect as a proportion of the image size. 115 * @param centre the center 116 * @see #getCentre 117 */ 118 public void setCentre( Point2D centre ) { 119 this.centreX = (float)centre.getX(); 120 this.centreY = (float)centre.getY(); 121 } 122 123 /** 124 * Get the centre of the effect as a proportion of the image size. 125 * @return the center 126 * @see #setCentre 127 */ 128 public Point2D getCentre() { 129 return new Point2D.Float( centreX, centreY ); 130 } 131 132 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 133 int width = src.getWidth(); 134 int height = src.getHeight(); 135 icentreX = width * centreX; 136 icentreY = height * centreY; 137 if (a == 0) 138 a = width/2; 139 if (b == 0) 140 b = height/2; 141 a2 = a*a; 142 b2 = b*b; 143 return super.filter( src, dst ); 144 } 145 146 protected void transformInverse(int x, int y, float[] out) { 147 float dx = x-icentreX; 148 float dy = y-icentreY; 149 float x2 = dx*dx; 150 float y2 = dy*dy; 151 if (y2 >= (b2 - (b2*x2)/a2)) { 152 out[0] = x; 153 out[1] = y; 154 } else { 155 float rRefraction = 1.0f / refractionIndex; 156 157 float z = (float)Math.sqrt((1.0f - x2/a2 - y2/b2) * (a*b)); 158 float z2 = z*z; 159 160 float xAngle = (float)Math.acos(dx / Math.sqrt(x2+z2)); 161 float angle1 = ImageMath.HALF_PI - xAngle; 162 float angle2 = (float)Math.asin(Math.sin(angle1)*rRefraction); 163 angle2 = ImageMath.HALF_PI - xAngle - angle2; 164 out[0] = x - (float)Math.tan(angle2)*z; 165 166 float yAngle = (float)Math.acos(dy / Math.sqrt(y2+z2)); 167 angle1 = ImageMath.HALF_PI - yAngle; 168 angle2 = (float)Math.asin(Math.sin(angle1)*rRefraction); 169 angle2 = ImageMath.HALF_PI - yAngle - angle2; 170 out[1] = y - (float)Math.tan(angle2)*z; 171 } 172 } 173 174 public String toString() { 175 return "Distort/Sphere..."; 176 } 177 178}