/* * ------------------------------------------------------------------------- * $Id: CsPanel.java,v 1.3 2004/04/07 20:08:26 estewart Exp $ * ------------------------------------------------------------------------- * Copyright (c) 1999 Visual Numerics Inc. All Rights Reserved. * * This software is confidential information which is proprietary to * and a trade secret of Visual Numerics, Inc. Use, duplication or * disclosure is subject to the terms of an appropriate license * agreement. * * VISUAL NUMERICS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. VISUAL * NUMERICS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR * ITS DERIVATIVES. *-------------------------------------------------------------------------- */ /* * CsPanel.java * * Created on August 19, 2003, 2:15 PM */ package com.imsl.demo.fitting; import com.imsl.chart.*; import com.imsl.math.*; import java.util.Vector; import java.awt.event.*; import javax.swing.JOptionPane; public class CsPanel extends javax.swing.JPanel implements ActionListener, MouseListener { private Chart chart; private AxisXY axis; private Data point; private Vector dataX, dataY; private double[] xRange, yRange; private final int numMethod = 6; private Data line[] = new Data[numMethod]; private javax.swing.JFrame parentFrame; private javax.swing.JRadioButtonMenuItem[] jRadioButtons; private final int numData = 5; private final String dataName[] = {"Blank", "Coffee Sales", "Titanium Data", "Ocean Depth", "Sin(x) Function"}; /** Creates new form CsPanel */ public CsPanel(javax.swing.JFrame parent) { this.parentFrame = parent; dataX = new Vector(); dataY = new Vector(); initComponents(); setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.85*parent.getSize().height))); jButtonGenerate.addActionListener(this); jButtonEnter.addActionListener(this); jButtonReset.addActionListener(this); checkAkima.addActionListener(this); checkInterp.addActionListener(this); checkPeriod.addActionListener(this); checkShape.addActionListener(this); checkSmooth.addActionListener(this); checkSmooth2.addActionListener(this); addDataButtons(); setChart(); jPanelChart.setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.66*parent.getSize().height))); getData(); update(); } private void setChart() { chart = jPanelChart.getChart(); chart.getLegend().setPaint(true); chart.getLegend().setViewport(0.8,0.95,0.05,0.15); axis = new AxisXY(chart); axis.setViewport(0.12,0.78,0.05,0.88); // Set axes ranges axis.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisX().setWindow(0.0, 50.0); axis.getAxisY().setWindow(0.0, 75.0); axis.getAxisX().setTextFormat(new java.text.DecimalFormat("###.#")); axis.getAxisY().setTextFormat(new java.text.DecimalFormat("###.#")); // Add MouseListeren to the chart. jPanelChart.addMouseListener(this); } // add the available data sets to the dataMenu private void addDataButtons() { jRadioButtons = new javax.swing.JRadioButtonMenuItem[numData]; javax.swing.ButtonGroup group = new javax.swing.ButtonGroup(); for (int i=0; i<numData; i++) { jRadioButtons[i] = new javax.swing.JRadioButtonMenuItem(); jRadioButtons[i].setText(dataName[i]); jRadioButtons[i].addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { getData(); update(); } }); group.add(jRadioButtons[i]); ((FittingMain)parentFrame).getDataMenu().add(jRadioButtons[i]); } jRadioButtons[1].setSelected(true); } // clear and load data sets determined by the menu selection public void getData() { dataX.clear(); dataY.clear(); xRange = new double[2]; yRange = new double[2]; String xTitle = "X Value"; String yTitle = "Y Value"; String xFormat = "###.#"; String yFormat = "###.#"; int selected = -1; for (int i=0; i<numData; i++) { if (jRadioButtons[i].isSelected()) { selected = i; break; } } switch (selected) { case 0: // blank xRange[0] = 0.0; xRange[1] = 50.0; yRange[0] = 0.0; yRange[1] = 50.0; break; case 3: /* These data are the depth of the Atlantic Ocean from * Cape Hatteras, North America to Cape Blanc, Africa */ double x3[] = {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60}; double y3[] = {0,46,52,47,52,56,55,42,25,49,55,60,58,51,42,0}; for (int i=0; i<x3.length; i++) { dataX.add(new Double(x3[i]*100)); dataY.add(new Double(y3[i]*-100)); } xTitle = "Distance, km"; yTitle = "Depth, m"; xFormat = "#,###"; yFormat = "#,###"; xRange[0] = 0.0; xRange[1] = 6000.0; yRange[0] = -6500.0; yRange[1] = 0.0; break; case 1: /* These data * data discussed by Neter and Wasserman (1974, * pp. 279–285). The data set contains the response variable y measuring coffee * sales (in hundred gallons) and the number of self-service coffee dispensers. */ //double x2[] = {53,61,69,77,85,93,101,109,117,125,133,141,149,157,165,173,181,189,197,205,213,221,229,237}; //double y2[] = {8103,6044,4694,3827,3086,3540,3941,2033,1703,1242,1310,1332,1486,2066,2888,2059,2153,1874,1919,1575,1434,1153,942,756}; //xRange[1] = 250.0; //yRange[1] = 8500.0; double x1[] = {0,1,2,4,5,6,7}; double y1[] = {508.1,568.2,651.7,755.3,787.6,841.4,854.7,}; xRange[1] = 8; yRange[1] = 1000.0; for (int i=0; i<x1.length; i++) { dataX.add(new Double(x1[i])); dataY.add(new Double(y1[i])); } xTitle = "Number of Self-Service Dispensers"; yTitle = "Coffee Sales, Hundreds of Gallons"; xFormat = "###"; yFormat = "###"; xRange[0] = 0.0; yRange[0] = 0.0; break; case 2: /* These data are from A Practical Guide to Splines by C. de Boor * these data represent a property of titanium as a function of * temperature. They have been used extensively as an example in spline * approximation with variable knots. * The peak near 885 degrees C is the point of phase change to the beta phase */ double y2[] = {.644,.622,.638,.649,.652,.639,.646,.657,.652,.655,.644,.663,.663,.668,.676,.676,.686,.679,.678,.683,.694,.699,.710,.730,.763,.812,.907,1.044,1.336,1.881,2.169,2.075,1.598,1.211,.916,.746,.672,.627,.615,.607,.606,.609,.603,.601,.603,.601,.611,.601,.608}; for (int i=0; i<y2.length; i++) { dataX.add(new Double(585 + 10.0*(i+1))); dataY.add(new Double(y2[i])); } xTitle = "Temperature, "+(char)186+"C"; yTitle = "Specific Heat of Titanium, J/gK"; xFormat = "#,###"; yFormat = "#.#"; xRange[0] = 550.0; xRange[1] = 1100.0; yRange[0] = 0.5; yRange[1] = 2.5; break; case 4: /* This is a sin() function */ int num = 14; for (int i=0; i<num; i++) { double x = (double)i; dataX.add(new Double(x)); dataY.add(new Double(Math.sin(x))); } xTitle = "X Value"; yTitle = "Sin(X)"; xFormat = "##.#"; yFormat = "##.#"; xRange[0] = 0.0; xRange[1] = num; yRange[0] = -2.0; yRange[1] = 2.0; break; } axis.getAxisX().getAxisTitle().setTitle(xTitle); axis.getAxisY().getAxisTitle().setTitle(yTitle); axis.getAxisX().setWindow(xRange); axis.getAxisY().setWindow(yRange); axis.getAxisX().setTextFormat(new java.text.DecimalFormat(xFormat)); axis.getAxisY().setTextFormat(new java.text.DecimalFormat(yFormat)); } // Draw the graph. private void drawGraph() { if ((dataX.size() != 0)) { double[] x = new double[dataX.size()]; double[] y = new double[dataY.size()]; for (int i = 0; i < x.length; i++) { x[i] = ((Double) dataX.get(i)).doubleValue(); y[i] = ((Double) dataY.get(i)).doubleValue(); } // Draw the points. point = new Data(axis, x, y); point.setDataType(Data.DATA_TYPE_MARKER); point.setMarkerType(Data.MARKER_TYPE_OCTAGON_X); point.setMarkerSize(0.8); point.setMarkerColor(java.awt.Color.blue); // Draw the spline using CsAkima if (checkAkima.isSelected() && (dataX.size() > 3)) { final CsAkima cs0 = new CsAkima(x, y); ChartFunction fcn0 = new ChartFunction() { public double f(double x) { return cs0.value(x); } }; line[0] = new Data(axis, fcn0, xRange[0], xRange[1]); line[0].setLineColor(java.awt.Color.magenta); line[0].setTitle("CsAkima"); line[0].setLineWidth(1.5); } // Draw the spline using CsInterpolate if (checkInterp.isSelected() && (dataX.size() > 2)) { final CsInterpolate cs1 = new CsInterpolate(x, y); ChartFunction fcn1 = new ChartFunction() { public double f(double x) { return cs1.value(x); } }; line[1] = new Data(axis, fcn1, xRange[0], xRange[1]); line[1].setLineColor(java.awt.Color.green); line[1].setTitle("CsInterpolate"); line[1].setLineWidth(1.5); } // Draw the spline using CsPeriodic if (checkPeriod.isSelected() && (dataX.size() > 3)) { final CsPeriodic cs2 = new CsPeriodic(x, y); ChartFunction fcn2 = new ChartFunction() { public double f(double x) { return cs2.value(x); } }; line[2] = new Data(axis, fcn2, xRange[0], xRange[1]); line[2].setLineColor(java.awt.Color.orange); line[2].setTitle("CsPeriodic"); line[2].setLineWidth(1.5); } // Draw the spline using CsShape if (checkShape.isSelected() && (dataX.size() > 2)) { try { final CsShape cs3 = new CsShape(x, y); ChartFunction fcn3 = new ChartFunction() { public double f(double x) { return cs3.value(x); } }; line[3] = new Data(axis, fcn3, xRange[0], xRange[1]); line[3].setLineColor(java.awt.Color.blue); line[3].setTitle("CsShape"); line[3].setLineWidth(1.5); } catch (CsShape.TooManyIterationsException e) { System.out.println("Too many iterations"); } catch (SingularMatrixException e) { System.out.println("Singular matrix"); } } // Draw the spline using CsSmooth if (checkSmooth.isSelected() && (dataX.size() > 2)) { final CsSmooth cs4 = new CsSmooth(x, y); ChartFunction fcn4 = new ChartFunction() { public double f(double x) { return cs4.value(x); } }; line[4] = new Data(axis, fcn4, xRange[0], xRange[1]); line[4].setLineColor(java.awt.Color.cyan); line[4].setTitle("CsSmooth"); line[4].setLineWidth(1.5); } // Draw the spline using CsSmooth2 if (checkSmooth2.isSelected()) { // Set the weights final double sdev = 1./Math.sqrt(3.); double weights[] = new double[dataX.size()]; for (int i = 0; i < dataX.size(); i++) { weights[i] = sdev; } // Set the smoothing parameter double smpar = (double)dataX.size(); final CsSmoothC2 cs5 = new CsSmoothC2(x, y, weights, smpar); ChartFunction fcn5 = new ChartFunction() { public double f(double x) { return cs5.value(x); } }; line[5] = new Data(axis, fcn5, xRange[0], xRange[1]); line[5].setLineColor(java.awt.Color.red); line[5].setTitle("CsSmoothC2"); line[5].setLineWidth(1.5); } } } // Redraw the chart. private void update() { for (int i = 0; i<numMethod; i++) { if (line[i] != null) line[i].remove(); } if (point != null) point.remove(); drawGraph(); repaint(); } public void setVisible(boolean show) { super.setVisible(show); if (show) { addDataButtons(); } } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ private void initComponents() {//GEN-BEGIN:initComponents jPanel = new javax.swing.JPanel(); jButtonEnter = new javax.swing.JButton(); jButtonGenerate = new javax.swing.JButton(); jLabelPoints = new javax.swing.JLabel(); numField = new javax.swing.JTextField("6", 4); jButtonReset = new javax.swing.JButton(); jPanel1 = new javax.swing.JPanel(); jLabel2 = new javax.swing.JLabel(); jPanelChecks = new javax.swing.JPanel(); checkAkima = new javax.swing.JCheckBox(); checkInterp = new javax.swing.JCheckBox(); checkPeriod = new javax.swing.JCheckBox(); checkShape = new javax.swing.JCheckBox(); checkSmooth = new javax.swing.JCheckBox(); checkSmooth2 = new javax.swing.JCheckBox(); jPanelChart = new com.imsl.chart.JPanelChart(); setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS)); setPreferredSize(new java.awt.Dimension(500, 600)); jPanel.setMaximumSize(new java.awt.Dimension(32767, 36)); jButtonEnter.setText("Enter Points"); jPanel.add(jButtonEnter); jButtonGenerate.setText("Generate"); jPanel.add(jButtonGenerate); jLabelPoints.setText("# of Points: "); jPanel.add(jLabelPoints); numField.setColumns(4); numField.setText("6"); jPanel.add(numField); jButtonReset.setText("Reset"); jPanel.add(jButtonReset); add(jPanel); jPanel1.setMaximumSize(new java.awt.Dimension(32767, 20)); jPanel1.setMinimumSize(new java.awt.Dimension(93, 20)); jPanel1.setPreferredSize(new java.awt.Dimension(93, 20)); jLabel2.setText("Select Cubic Spline Models:"); jPanel1.add(jLabel2); add(jPanel1); jPanelChecks.setMaximumSize(new java.awt.Dimension(32767, 28)); jPanelChecks.setMinimumSize(new java.awt.Dimension(468, 28)); jPanelChecks.setPreferredSize(new java.awt.Dimension(468, 28)); checkAkima.setText("Akima"); jPanelChecks.add(checkAkima); checkInterp.setSelected(true); checkInterp.setText("Interpolate"); jPanelChecks.add(checkInterp); checkPeriod.setText("Periodic"); jPanelChecks.add(checkPeriod); checkShape.setText("Shape"); jPanelChecks.add(checkShape); checkSmooth.setText("Smooth"); jPanelChecks.add(checkSmooth); checkSmooth2.setText("SmoothC2"); jPanelChecks.add(checkSmooth2); add(jPanelChecks); jPanelChart.setMinimumSize(new java.awt.Dimension(500, 500)); jPanelChart.setPreferredSize(new java.awt.Dimension(500, 500)); add(jPanelChart); }//GEN-END:initComponents // Implement ActionListener public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Enter Points")) { // Enter points using a text area. javax.swing.JTextArea textArea = new javax.swing.JTextArea(10, 5); javax.swing.JScrollPane scroll = new javax.swing.JScrollPane(textArea); int option = 0; try { option = JOptionPane.showConfirmDialog(this, scroll, "Enter Points", JOptionPane.OK_CANCEL_OPTION); if (option == JOptionPane.CANCEL_OPTION) return; } catch (Exception ex) { } java.util.StringTokenizer lineToken = new java.util.StringTokenizer(textArea.getText(), "\n"); boolean dup = false; while (lineToken.hasMoreElements()) { java.util.StringTokenizer token = new java.util.StringTokenizer(lineToken.nextToken(), "(){}[] ,\t\n"); // If the line does not contain 2 numbers, then ignore. if (token.countTokens() == 2) { try { double x = Double.parseDouble(token.nextToken()); double y = Double.parseDouble(token.nextToken()); // Ignore any points that are not in the range. if ((x >= xRange[0]) && (x <= xRange[1]) && (y >= yRange[0]) && (y <= yRange[1])) { // Only add if the x value is distinct or else // we'll throw a nasty java.lang.IllegalArgumentException for (int i = 0; i < dataX.size(); i++) { if (((Double) dataX.get(i)).doubleValue() == x) { dup = true; } } if (!dup) { dataX.add(new Double(x)); dataY.add(new Double(y)); } } } catch (Exception ex) { } } } if (dup) { JOptionPane.showMessageDialog(this, "X values must be distinct.\n" + "Duplicates have not been added.", "Data Error", JOptionPane.ERROR_MESSAGE); } update(); } else if (e.getActionCommand().equals("Generate")) { int i = 0; try { i = Integer.parseInt(numField.getText()); } catch (Exception exception) { i = 6; numField.setText("6"); } finally { if (i <= 0) { i = 6; numField.setText("6"); } for (int j = 0; j < i; j++) { dataX.add(new Double(xRange[1] * Math.random() + xRange[0])); dataY.add(new Double(yRange[1] * Math.random() + yRange[0])); } update(); } } else if (e.getActionCommand().equals("Reset")) { numField.setText("6"); dataX = new Vector(); dataY = new Vector(); update(); getData(); update(); } else { // this means a checkbox is changed update(); } } // Implement MouseListener public void mouseClicked(MouseEvent e) { double user[] = {0,0}; axis.mapDeviceToUser(e.getX(), e.getY(), user); // Do not add the point if it is not in the range. if ((user[0] < xRange[0]) || (user[0] > xRange[1]) || (user[1] < yRange[0]) || (user[1] > yRange[1])) return; // Button is to add points. Otherwise, remove points. if (e.getModifiers() == MouseEvent.BUTTON1_MASK) { // But only add if the x value is distinct or else // Splines throw a java.lang.IllegalArgumentException boolean dup = false; for (int i = 0; i < dataX.size(); i++) { if (((Double) dataX.get(i)).doubleValue() == (double) user[0]) { dup = true; } } if (dup) { JOptionPane.showMessageDialog(this, "X values must be distinct.", "Data Error", JOptionPane.ERROR_MESSAGE); } else { dataX.add(new Double(user[0])); dataY.add(new Double(user[1])); update(); } } else { int idx = -1; double min = 0.01; final double ux = (user[0]-xRange[0])/(double)(xRange[1]-xRange[0]); final double uy = (user[1]-yRange[0])/(double)(yRange[1]-yRange[0]); for (int i = 0; i < dataX.size(); i++) { double x = (((Double)dataX.get(i)).doubleValue()-xRange[0])/ (double)(xRange[1]-xRange[0]); double y = (((Double)dataY.get(i)).doubleValue()-yRange[0])/ (double)(yRange[1]-yRange[0]); double dist = Math.sqrt((ux - x)*(ux - x) + (uy - y)*(uy - y)); if (dist < min) { min = dist; idx = i; } } if (idx != -1) { dataX.remove(idx); dataY.remove(idx); update(); } } } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox checkSmooth; private javax.swing.JLabel jLabelPoints; private javax.swing.JButton jButtonGenerate; private javax.swing.JCheckBox checkShape; private javax.swing.JButton jButtonReset; private javax.swing.JTextField numField; private javax.swing.JLabel jLabel2; private javax.swing.JCheckBox checkInterp; private javax.swing.JCheckBox checkPeriod; private com.imsl.chart.JPanelChart jPanelChart; private javax.swing.JCheckBox checkSmooth2; private javax.swing.JCheckBox checkAkima; private javax.swing.JPanel jPanel1; private javax.swing.JButton jButtonEnter; private javax.swing.JPanel jPanel; private javax.swing.JPanel jPanelChecks; // End of variables declaration//GEN-END:variables }