/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.display2d; import java.awt.Color; import javax.swing.JFrame; import javax.swing.WindowConstants; import org.opensourcephysics.display.InteractivePanel; import org.opensourcephysics.display.axes.XAxis; import org.opensourcephysics.display.axes.XYAxis; public class ComplexColorMapper { static final double PI2 = Math.PI*2; static final double COLOR_ERR = 1.0E-9; private double ceil; private Color ceilColor = Color.lightGray; private JFrame legendFrame; int[] reds = new int[256]; int[] greens = new int[256]; int[] blues = new int[256]; protected ZExpansion zMap = null; /** * Constructor ComplexColorMapper * @param _ceil */ public ComplexColorMapper(double _ceil) { ceil = _ceil; if(zMap!=null) { zMap.setMinMax(0, ceil); } initColors(); } public static JFrame showPhaseLegend() { InteractivePanel dp = new InteractivePanel(); dp.setPreferredSize(new java.awt.Dimension(300, 66)); dp.setPreferredGutters(0, 0, 0, 35); dp.setClipAtGutter(false); JFrame legendFrame = new JFrame("Complex Phase"); //$NON-NLS-1$ legendFrame.setResizable(false); legendFrame.setContentPane(dp); int numPts = 360; GridPointData pointdata = new GridPointData(numPts, 1, 3); double[][][] data = pointdata.getData(); double theta = -Math.PI, delta = 2*Math.PI/(numPts); for(int i = 0, n = data.length; i<n; i++) { data[i][0][2] = 0.999; data[i][0][3] = Math.cos(theta); data[i][0][4] = Math.sin(theta); theta += delta; } pointdata.setScale(-Math.PI, Math.PI, 0, 1); Plot2D plot = new ComplexGridPlot(pointdata); plot.setShowGridLines(false); plot.update(); dp.addDrawable(plot); XAxis xaxis = new XAxis(""); //$NON-NLS-1$ xaxis.setLocationType(XYAxis.DRAW_AT_LOCATION); xaxis.setLocation(-0.5); xaxis.setEnabled(true); dp.addDrawable(xaxis); legendFrame.pack(); legendFrame.setVisible(true); return legendFrame; } /** * Shows the phase legend. */ public JFrame showLegend() { InteractivePanel dp = new InteractivePanel(); dp.setPreferredSize(new java.awt.Dimension(300, 66)); dp.setPreferredGutters(0, 0, 0, 35); dp.setClipAtGutter(false); if((legendFrame==null)||!legendFrame.isDisplayable()) { legendFrame = new JFrame("Complex Phase"); //$NON-NLS-1$ } legendFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); legendFrame.setResizable(false); legendFrame.setContentPane(dp); int numPts = 360; GridPointData pointdata = new GridPointData(numPts, 1, 3); double[][][] data = pointdata.getData(); double theta = -Math.PI, delta = 2*Math.PI/(numPts); for(int i = 0, n = data.length; i<n; i++) { data[i][0][2] = 0.999; data[i][0][3] = Math.cos(theta); data[i][0][4] = Math.sin(theta); theta += delta; } pointdata.setScale(-Math.PI, Math.PI, 0, 1); Plot2D plot = new ComplexGridPlot(pointdata); plot.setShowGridLines(false); plot.update(); dp.addDrawable(plot); XAxis xaxis = new XAxis(""); //$NON-NLS-1$ xaxis.setLocationType(XYAxis.DRAW_AT_LOCATION); xaxis.setLocation(-0.5); xaxis.setEnabled(true); dp.addDrawable(xaxis); legendFrame.pack(); legendFrame.setVisible(true); return legendFrame; } /** * Sets the z scale. * @param _ceil */ public void setScale(double _ceil) { ceil = _ceil; if(zMap!=null) { zMap.setMinMax(0, ceil); } } /** * Converts a double to color components. * * @param samples double[] * @param rgb byte[] * @return byte[] */ public byte[] samplesToComponents(double[] samples, byte[] rgb) { Color color = samplesToColor(samples); rgb[0] = (byte) color.getRed(); rgb[1] = (byte) color.getGreen(); rgb[2] = (byte) color.getBlue(); return rgb; } /** * Converts a phase angle in the range [-Pi,Pi] to hue, saturation, and brightness. * * @param phi phase angle * @return the HSB color */ public Color phaseToColor(double phi) { float b = 1; // brightness float h = (float) ((Math.PI+phi)/PI2); int index = ((int) (255*h)); return new Color((int) (b*reds[index]), (int) (b*greens[index]), (int) (b*blues[index])); } /** * Converts a complex number to hue, saturation, and brightness. * @param re * @param im * @return the HSB color */ public Color complexToColor(double re, double im) { float b = 1; // brightness float h = (float) ((Math.PI+Math.atan2(im, re))/PI2); int index = ((int) (255*h)); return new Color((int) (b*reds[index]), (int) (b*greens[index]), (int) (b*blues[index])); } /** * Converts an array of samples to hue, saturation, and brightness. * Samples contains magnitude, re, and im. * @param samples * @return the HSB color */ public Color samplesToColor(double[] samples) { double zval = samples[0]; if(zMap!=null) { zval = zMap.evaluate(zval); } if(zval<=0) { return Color.black; } else if((zMap==null)&&(zval>ceil+COLOR_ERR)) { return ceilColor; } else { zval = Math.min(zval, ceil); } float b = (float) (zval/ceil); // brightness float h = (float) ((Math.PI+Math.atan2(samples[2], samples[1]))/PI2); // hue int index = ((int) (255*h)); return new Color((int) (b*reds[index]), (int) (b*greens[index]), (int) (b*blues[index])); } /** * Converts a vertex point array of samples to hue, saturation, and brightness. * * A vertex containing x, y, magnitude, re, and im. * * @param vertex the point * @return the HSB color */ public Color pointToColor(double[] vertex) { double zval = vertex[2]; if(zMap!=null) { zval = zMap.evaluate(zval); } if(zval<=0) { return Color.black; } else if(zval>ceil+COLOR_ERR) { return ceilColor; } float b = (float) (zval/ceil); float h = (float) ((Math.PI+Math.atan2(vertex[4], vertex[3]))/PI2); int index = ((int) (255*h)); return new Color((int) (b*reds[index]), (int) (b*greens[index]), (int) (b*blues[index])); // return Color.getHSBColor(h,1,b); } /** * Sets map for z values. * * @param map ZExpansion */ public void setZMap(ZExpansion map) { zMap = map; if(zMap!=null) { zMap.setMinMax(0, ceil); } } /** * Gets the ceiling color. * @return */ public double getCeil() { return ceil; } /** * Gets the ceiling color. * @return */ public Color getCeilColor() { return ceilColor; } /** * Sets the ceiling. * * @param _ceilColor */ public void setCeilColor(Color _ceilColor) { ceilColor = _ceilColor; } private void initColors() { double pi = Math.PI; for(int i = 0; i<256; i++) { double val = Math.abs(Math.sin(pi*i/255)); blues[i] = (int) (255*val*val); val = Math.abs(Math.sin(pi*i/255+pi/3)); greens[i] = (int) (255*val*val*Math.sqrt(val)); val = Math.abs(Math.sin(pi*i/255+2*pi/3)); reds[i] = (int) (255*val*val); } } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */