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 distorts an image by twisting it from the centre out. 025 * The twisting is centred at the centre of the image and extends out to the smallest of 026 * the width and height. Pixels outside this radius are unaffected. 027 */ 028public class TwirlFilter extends TransformFilter { 029 030 private float angle = 0; 031 private float centreX = 0.5f; 032 private float centreY = 0.5f; 033 private float radius = 100; 034 035 private float radius2 = 0; 036 private float icentreX; 037 private float icentreY; 038 039 /** 040 * Construct a TwirlFilter with no distortion. 041 */ 042 public TwirlFilter() { 043 setEdgeAction( CLAMP ); 044 } 045 046 /** 047 * Set the angle of twirl in radians. 0 means no distortion. 048 * @param angle the angle of twirl. This is the angle by which pixels at the nearest edge of the image will move. 049 * @see #getAngle 050 */ 051 public void setAngle(float angle) { 052 this.angle = angle; 053 } 054 055 /** 056 * Get the angle of twist. 057 * @return the angle in radians. 058 * @see #setAngle 059 */ 060 public float getAngle() { 061 return angle; 062 } 063 064 /** 065 * Set the centre of the effect in the X direction as a proportion of the image size. 066 * @param centreX the center 067 * @see #getCentreX 068 */ 069 public void setCentreX( float centreX ) { 070 this.centreX = centreX; 071 } 072 073 /** 074 * Get the centre of the effect in the X direction as a proportion of the image size. 075 * @return the center 076 * @see #setCentreX 077 */ 078 public float getCentreX() { 079 return centreX; 080 } 081 082 /** 083 * Set the centre of the effect in the Y direction as a proportion of the image size. 084 * @param centreY the center 085 * @see #getCentreY 086 */ 087 public void setCentreY( float centreY ) { 088 this.centreY = centreY; 089 } 090 091 /** 092 * Get the centre of the effect in the Y direction as a proportion of the image size. 093 * @return the center 094 * @see #setCentreY 095 */ 096 public float getCentreY() { 097 return centreY; 098 } 099 100 /** 101 * Set the centre of the effect as a proportion of the image size. 102 * @param centre the center 103 * @see #getCentre 104 */ 105 public void setCentre( Point2D centre ) { 106 this.centreX = (float)centre.getX(); 107 this.centreY = (float)centre.getY(); 108 } 109 110 /** 111 * Get the centre of the effect as a proportion of the image size. 112 * @return the center 113 * @see #setCentre 114 */ 115 public Point2D getCentre() { 116 return new Point2D.Float( centreX, centreY ); 117 } 118 119 /** 120 * Set the radius of the effect. 121 * @param radius the radius 122 * @min-value 0 123 * @see #getRadius 124 */ 125 public void setRadius(float radius) { 126 this.radius = radius; 127 } 128 129 /** 130 * Get the radius of the effect. 131 * @return the radius 132 * @see #setRadius 133 */ 134 public float getRadius() { 135 return radius; 136 } 137 138 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 139 icentreX = src.getWidth() * centreX; 140 icentreY = src.getHeight() * centreY; 141 if ( radius == 0 ) 142 radius = Math.min(icentreX, icentreY); 143 radius2 = radius*radius; 144 return super.filter( src, dst ); 145 } 146 147 protected void transformInverse(int x, int y, float[] out) { 148 float dx = x-icentreX; 149 float dy = y-icentreY; 150 float distance = dx*dx + dy*dy; 151 if (distance > radius2) { 152 out[0] = x; 153 out[1] = y; 154 } else { 155 distance = (float)Math.sqrt(distance); 156 float a = (float)Math.atan2(dy, dx) + angle * (radius-distance) / radius; 157 out[0] = icentreX + distance*(float)Math.cos(a); 158 out[1] = icentreY + distance*(float)Math.sin(a); 159 } 160 } 161 162 public String toString() { 163 return "Distort/Twirl..."; 164 } 165 166}