グラデェーション
スプライン関数を利用して、グラデーションを生成するクラスを作ってみる。
■ソースコード
次のようなコードを書いてみた。
インターフェイスGradientを定義し、オブジェクトはGradientFactoryで生成する。
・Gradient.java
package test; import java.awt.Color; public interface Gradient { public Color getColor(double arg); public float[] getColorByFloat(double arg); public int getColorByInt(double arg); }
・GradientFactory.java
package test; import java.awt.Color; public class GradientFactory { public static final Color[] GRADIENT_RGB=new Color[]{Color.BLUE,Color.GREEN,Color.RED}; public static final Color[] GRADIENT_NATURAL_COLOR=new Color[]{Color.GREEN,new Color(187,135,12),Color.WHITE}; private GradientFactory(){} public static Gradient createGradient(Color[] colors){ if(colors.length==2){ LinerGradient ret=new LinerGradient(colors,1.0); return ret; }else if(colors.length>2){ SplineGradient ret=new SplineGradient(colors,1.0); return ret; }else{ throw new IllegalArgumentException(); } } public static Gradient createGradient(Color[] colors,double order){ if(colors.length==2){ LinerGradient ret=new LinerGradient(colors,order); return ret; }else if(colors.length>2){ SplineGradient ret=new SplineGradient(colors,order); return ret; }else{ throw new IllegalArgumentException(); } } private static class LinerGradient implements Gradient{ private double[][] color; private double order=1.0; public LinerGradient(Color[] c,double o){ color=new double[3][2]; color[0][0]=(double)c[0].getRed(); color[0][1]=(double)c[1].getRed(); color[1][0]=(double)c[0].getGreen(); color[1][1]=(double)c[1].getGreen(); color[2][0]=(double)c[0].getBlue(); color[2][1]=(double)c[1].getBlue(); order=o; } @Override public Color getColor(double arg) { double val=Math.pow(arg, order); if(val<0)val=0; if(val>1.0)val=1.0; int r=(int)((color[0][1]-color[0][0])*val+color[0][0]); int g=(int)((color[1][1]-color[1][0])*val+color[1][0]); int b=(int)((color[2][1]-color[2][0])*val+color[2][0]); Color ret=new Color(r,g,b,255); return ret; } @Override public float[] getColorByFloat(double arg) { double val=Math.pow(arg, order); if(val<0)val=0; if(val>1.0)val=1.0; float r=(float)((color[0][1]-color[0][0])*val+color[0][0])/255.0f; float g=(float)((color[1][1]-color[1][0])*val+color[1][0])/255.0f; float b=(float)((color[2][1]-color[2][0])*val+color[2][0])/255.0f; return new float[]{r,g,b,1.0f}; } @Override public int getColorByInt(double arg) { double val=Math.pow(arg, order); if(val<0)val=0; if(val>1.0)val=1.0; int r=(int)((color[0][1]-color[0][0])*val+color[0][0]); int g=(int)((color[1][1]-color[1][0])*val+color[1][0]); int b=(int)((color[2][1]-color[2][0])*val+color[2][0]); if(r<0)r=0; if(r>255)r=255; if(g<0)g=0; if(g>255)g=255; if(b<0)b=0; if(b>255)b=255; int ret=(255<<24)+(r<<16)+(g<<8)+b; return ret; } } private static class SplineGradient implements Gradient{ private double[][] color; private double[] value; private Spline[] spline; private double order=1.0; public SplineGradient(Color[] c,double o){ color=new double[3][c.length]; value=new double[c.length]; spline=new Spline[3]; for(int i=0;i<c.length;i++){ color[0][i]=(double)c[i].getRed(); color[1][i]=(double)c[i].getGreen(); color[2][i]=(double)c[i].getBlue(); value[i]=(float)i/(float)(color.length-1); } spline[0]=new Spline(value,color[0]); spline[1]=new Spline(value,color[1]); spline[2]=new Spline(value,color[2]); order=o; } public Color getColor(double v){ if(Double.isNaN(v)||Double.isInfinite(v)){ throw new ArithmeticException("NaN"); }else{ double val=Math.pow(v, order); if(val<0)val=0; if(val>1.0)val=1.0; int r=(int)(spline[0].interpolate(val)); int g=(int)(spline[1].interpolate(val)); int b=(int)(spline[2].interpolate(val)); if(r<0)r=0; if(r>255)r=255; if(g<0)g=0; if(g>255)g=255; if(b<0)b=0; if(b>255)b=255; Color ret=new Color(r,g,b,255); return ret; } } public float[] getColorByFloat(double v){ if(Double.isNaN(v)||Double.isInfinite(v)){ throw new ArithmeticException("NaN"); }else{ double val=Math.pow(v, order); if(val<0)val=0; if(val>1.0)val=1.0; float r=(float)(spline[0].interpolate(val))/255.0f; float g=(float)(spline[1].interpolate(val))/255.0f; float b=(float)(spline[2].interpolate(val))/255.0f; if(r<0.0f)r=0.0f; if(r>1.0f)r=1.0f; if(g<0.0f)g=0.0f; if(g>1.0f)g=1.0f; if(b<0.0f)b=0.0f; if(b>1.0f)b=1.0f; return new float[]{r,g,b,1.0f}; } } @Override public int getColorByInt(double v) { if(Double.isNaN(v)||Double.isInfinite(v)){ throw new ArithmeticException("NaN"); }else{ double val=Math.pow(v, order); if(val<0)val=0; if(val>1.0)val=1.0; int r=(int)(spline[0].interpolate(val)); int g=(int)(spline[1].interpolate(val)); int b=(int)(spline[2].interpolate(val)); if(r<0)r=0; if(r>255)r=255; if(g<0)g=0; if(g>255)g=255; if(b<0)b=0; if(b>255)b=255; int ret=(255<<24)+(r<<16)+(g<<8)+b; return ret; } } } private static class Spline { private int num; private double[] x, y, z; public Spline(double[] _x,double[] _y){ num=_x.length; x=_x; y=_y; spline_NonCycle(); } double interpolate(double _x){ return interpolate_NonCycle(_x); } private void spline_NonCycle(){ z=new double[num]; double[] h=new double[num]; double[] d=new double[num]; z[0]=z[num-1]=0; for(int i=0;i<num-1;i++){ h[i]=x[i+1]-x[i]; d[i+1]=(y[i+1]-y[i])/ h[i]; } z[1]=d[2]-d[1]-h[0]*z[0]; d[1]=2*(x[2]-x[0]); for(int i=1;i<num-2;i++){ double t=h[i]/d[i]; z[i+1]=d[i+2]-d[i+1]-z[i]*t; d[i+1]=2*(x[i+2]-x[i])-h[i]*t; } z[num-2] -=h[num-2]*z[num-1]; for(int i=num-2;i>0;i--){ z[i]=(z[i]-h[i]*z[i+1])/d[i]; } } private double interpolate_NonCycle(double t){ int i=0; int j=num-1; while(i<j){ int k=(i+j)/2; if(x[k]<t){ i=k+1; }else{ j = k; } } if(i>0)i--; double h=x[i+1]-x[i]; double d=t-x[i]; return (((z[i+1]-z[i])*d/h+z[i]*3)*d +((y[i+1]-y[i])/ h -(z[i]*2+z[i+1])*h))*d+y[i]; } } }
・GradientPanel.java(テスト用)
package test; import java.awt.Color; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.LayoutManager; import java.awt.image.BufferedImage; import javax.swing.JFrame; import javax.swing.JPanel; public class GradientPanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; private enum GradientType{NORTH_SOUTH,WEST_EAST, NORTHWEST_SOUTHEAST, SOUTHWEST_NORTHEAST,CENTER} private int image_width,image_height; private BufferedImage image=null; private Gradient grad; private GradientType obj=GradientType.WEST_EAST; public GradientPanel(Gradient g,GradientType t) { super(); grad=g; obj=t; } public GradientPanel(boolean arg0,Gradient g,GradientType t) { super(arg0); grad=g; obj=t; } public GradientPanel(LayoutManager arg0, boolean arg1,Gradient g,GradientType t) { super(arg0, arg1); grad=g; obj=t; } public GradientPanel(LayoutManager arg0,Gradient g,GradientType t) { super(arg0); grad=g; obj=t; } @Override protected void paintComponent(Graphics arg0) { super.paintComponent(arg0); if(image_width!=getWidth()||image_height!=getHeight()){ createImage(); } if(image!=null){ arg0.drawImage(image, 0, 0, this); } } private void createImage(){ image_width=getWidth(); image_height=getHeight(); if(image_width==0||image_height==0){ image=null; return; } image=new BufferedImage(image_width,image_height,BufferedImage.TYPE_INT_ARGB); int[][] pixel=new int[image_width][image_height]; switch(obj){ case NORTH_SOUTH: initPixelsAtNS(pixel); break; case WEST_EAST: initPixelsAtWE(pixel); break; case NORTHWEST_SOUTHEAST: initPixelsAtNWSE(pixel); break; case SOUTHWEST_NORTHEAST: initPixelsAtSWNE(pixel); break; case CENTER: initPixelsAtCC(pixel); break; } for(int i=0;i<image_width;i++){ for(int j=0;j<image_height;j++){ image.setRGB(i, j, pixel[i][j]); } } } private void initPixelsAtNS(int[][] pixel){ double max=(double)pixel[0].length-1; for(int i=0;i<pixel[0].length;i++){ int val=grad.getColorByInt((double)i/max); for(int j=0;j<pixel.length;j++){ pixel[j][i]=val; } } } private void initPixelsAtWE(int[][] pixel){ double max=(double)pixel.length-1; for(int i=0;i<pixel.length;i++){ int val=grad.getColorByInt((double)i/max); for(int j=0;j<pixel[i].length;j++){ pixel[i][j]=val; } } } private void initPixelsAtCC(int[][] pixel){ double cx=((double)pixel.length)/2.0; double cy=((double)pixel[0].length)/2.0; double rr=Math.sqrt(cx*cx+cy*cy); for(int i=0;i<pixel.length;i++){ double xx=((double)i-cx); for(int j=0;j<pixel[i].length;j++){ double yy=((double)j-cy); double dist=Math.sqrt(xx*xx+yy*yy); pixel[i][j]=grad.getColorByInt(dist/rr); } } } private void initPixelsAtNWSE(int[][] pixel){ double ww=Math.sqrt((double)(image_width*image_width)+ (double)(image_height*image_height)); for(int i=0;i<pixel.length;i++){ for(int j=0;j<pixel[i].length;j++){ double dist=Math.sqrt((double)(i*i)+(double)(j*j)); pixel[i][j]=grad.getColorByInt(dist/ww); } } } private void initPixelsAtSWNE(int[][] pixel){ double ww=Math.sqrt((double)(image_width*image_width)+ (double)(image_height*image_height)); for(int i=0;i<pixel.length;i++){ for(int j=0;j<pixel[i].length;j++){ double dist=Math.sqrt((double)(i*i)+(double)(j*j)); pixel[i][j]=grad.getColorByInt(dist/ww); } } } public static void main(String[] args){ JFrame f=new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.getContentPane().setLayout(new GridLayout(2,2)); GradientPanel[] gp=new GradientPanel[4]; gp[0]=new GradientPanel(GradientFactory.createGradient( GradientFactory.GRADIENT_RGB), GradientPanel.GradientType.NORTH_SOUTH); gp[1]=new GradientPanel(GradientFactory.createGradient( GradientFactory.GRADIENT_NATURAL_COLOR), GradientPanel.GradientType.NORTHWEST_SOUTHEAST); gp[2]=new GradientPanel(GradientFactory.createGradient( new Color[]{Color.WHITE,Color.BLUE},1), GradientPanel.GradientType.CENTER); gp[3]=new GradientPanel(GradientFactory.createGradient( new Color[]{Color.WHITE,Color.BLUE},4), GradientPanel.GradientType.WEST_EAST); for(int i=0;i<gp.length;i++){ f.getContentPane().add(gp[i]); } f.setSize(320,240); f.setVisible(true); } }