/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2011 Andreas Maschke This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.swing; import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import javax.swing.JPanel; import org.jwildfire.base.Tools; import org.jwildfire.base.mathlib.MathLib; public class FormulaPanel extends JPanel { private static final long serialVersionUID = 1L; private double x[]; private double y[][]; public void setData(double pX[], double pY[][]) { x = pX; y = pY; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Color bgColor = Color.BLACK; Color borderColor = Color.WHITE; Color curveColor[] = { Color.YELLOW, Color.RED, Color.GREEN }; Rectangle bounds = getBounds(); int width = bounds.width; int height = bounds.height; g.setColor(bgColor); g.fillRect(0, 0, width, height); g.setColor(borderColor); g.drawRect(0, 0, width - 1, height - 1); // x = new double[100]; // y = new double[5][100]; // { // double xMin = 0.0; // double xMax = 1.0; // double dx = (xMax - xMin) / (pCount - 1); // double cx = xMin; // for (int i = 0; i < pCount; i++) { // x[i] = cx; // y[0][i] = x[i] * x[i]; // y[1][i] = x[i] * x[i] * x[i]; // y[2][i] = x[i] * x[i] * x[i] * x[i]; // y[3][i] = -0.5 * (1.0 - Math.exp(x[i])); // y[4][i] = 1.0 - Math.exp(-x[i]); // cx += dx; // } // } if ((x == null) || (y == null)) return; int pCount = x.length; // compute min/max double xMin = pCount > 0 ? x[0] : 0.0; double xMax = xMin; double yMin = pCount > 0 ? y[0][0] : 0.0; double yMax = yMin; for (int i = 1; i < pCount; i++) { if (x[i] < xMin) { xMin = x[i]; } else if (x[i] > xMax) { xMax = x[i]; } for (int j = 0; j < y.length; j++) { if (y[j][i] < yMin) { yMin = y[j][i]; } else if (y[j][i] > yMax) { yMax = y[j][i]; } } } if ((xMax - xMin) < MathLib.EPSILON) { xMax = xMin + MathLib.EPSILON; } if ((yMax - yMin) < MathLib.EPSILON) { yMax = yMin + MathLib.EPSILON; } // visual area double visXMin = xMin - (xMax - xMin) * 0.1; double visXMax = xMax + (xMax - xMin) * 0.1; double visYMin = yMin - (yMax - yMin) * 0.1; double visYMax = yMax + (yMax - yMin) * 0.1; // scaling factors double xScale = width / (visXMax - visXMin); double yScale = height / (visYMax - visYMin); int dxi = (int) (visXMin * xScale + 0.5); int dyi = (int) (visYMin * yScale + 0.5); // draw curve for (int j = 0; j < y.length; j++) { g.setColor(curveColor[j % curveColor.length]); int xi[] = new int[pCount]; int yi[] = new int[pCount]; for (int i = 0; i < pCount; i++) { xi[i] = (int) (x[i] * xScale + 0.5) - dxi; yi[i] = height - ((int) (y[j][i] * yScale + 0.5) - dyi); } g.drawPolyline(xi, yi, pCount); } // draw ticks g.setColor(borderColor); final int TICK_LENGTH = 7; final int LABEL_OFF = 3; final int X_TICKS = 3; int fontHeight = getFont().getSize(); { double xStep = calcTickStep(visXMax, visXMin, X_TICKS); double tickXMin = calcTickMinMax(visXMin, xStep); double tickXMax = calcTickMinMax(visXMax, xStep) + xStep; // System.out.println(tickXMin + " " + tickXMax + " " + xStep); double xt = tickXMin; while (xt + xStep < tickXMax + MathLib.EPSILON) { int xti = (int) (xt * xScale + 0.5) - dxi; g.drawLine(xti, 0, xti, TICK_LENGTH); g.drawLine(xti, height - 1, xti, height - 1 - TICK_LENGTH); String label = Tools.doubleToString(xt); g.drawString(label, xti - g.getFontMetrics().stringWidth(label) / 2, height - 1 - TICK_LENGTH - LABEL_OFF); xt += xStep; } } { final int yTicks = (int) ((double) height / (double) width * X_TICKS + 0.5); double yStep = calcTickStep(visYMax, visYMin, yTicks); double tickYMin = calcTickMinMax(visYMin, yStep); double tickYMax = calcTickMinMax(visYMax, yStep) + yStep; // System.out.println(tickYMin + " " + tickYMax + " " // + yStep); double yt = tickYMin; while (yt + yStep < tickYMax + MathLib.EPSILON) { int yti = height - ((int) (yt * yScale + 0.5) - dyi); g.drawLine(0, yti, TICK_LENGTH, yti); g.drawLine(width - 1, yti, width - 1 - TICK_LENGTH, yti); String label = Tools.doubleToString(yt); g.drawString(label, width - 1 - TICK_LENGTH - LABEL_OFF - g.getFontMetrics().stringWidth(label), yti + fontHeight / 2); yt += yStep; } } } private double calcTickMinMax(double pVisMin, double pStep) { double res = 0.0; if (pVisMin > 0.0) { while (res + pStep < pVisMin) { res += pStep; } } else { while (res - pStep > pVisMin) { res -= pStep; } } return res; } private double calcTickStep(double pVisMax, double pVisMin, int pTicks) { double res = (pVisMax - pVisMin) / (pTicks + 1); if (res < 1.0) { double v = res; res = 1.0; while (v < 1.0) { v *= 5.0; res /= 5.0; } } else { res = (int) (res + 0.5); } return res; } }