package jas.hist; import jas.plot.CoordinateTransformation; import jas.plot.DateCoordinateTransformation; import jas.plot.DoubleCoordinateTransformation; import jas.plot.MutableLegendEntry; import jas.plot.Overlay; import jas.plot.PlotGraphics; import jas.plot.Transformation; import java.awt.BasicStroke; import java.io.IOException; import java.io.Serializable; import java.util.Observable; class JASHist1DFunctionData extends JASHistData implements Serializable { private double lowerBound = Double.NaN; private double upperBound = Double.NaN; JASHist1DFunctionData(DataManager parent, Basic1DFunction ds) { super(parent); dataSource = ds; style = new JASHist1DFunctionStyle(); style.addObserver(this); } public void setStyle(JASHistStyle style) { if (!(style instanceof JASHist1DFunctionStyle)) throw new IllegalArgumentException("Style is not subclass of JASHist1DFunctionStyle"); if (this.style != null) this.style.deleteObserver(this); this.style = (JASHist1DFunctionStyle) style; style.addObserver(this); } public void update (Observable o, Object arg) { // Dragons: Likely to be called by different thread if (o == dataSource) ((SupportsFunctions) parent).update(this); else if (o == style) ((SupportsFunctions) parent).update(this); // overkill, we really just need a repaint } public void axisChanged() { ((SupportsFunctions) parent).update(this); } public void setXBounds(double xmin, double xmax) { this.lowerBound = xmin; this.upperBound = xmax; } void setXRange(double xmin, double xmax) { if ( ! Double.isNaN(lowerBound) ) xmin = xmin < lowerBound ? lowerBound : xmin; if ( ! Double.isNaN(upperBound) ) xmax = xmax > upperBound ? upperBound : xmax; if ( xmin > xmax ) xmin = xmax; if (overlay instanceof JASHistFunctionOverlay) ((JASHistFunctionOverlay) overlay).setXRange(xmin,xmax); } public String getTitle() { return dataSource.getTitle(); } Overlay createOverlay() { return new JASHistFunctionOverlay(this,style); } public JASHistStyle getStyle() { return style; } public DataSource getDataSource() { return dataSource; } void normalizationChanged(boolean now) { } public void writeAsXML(XMLPrintWriter pw, boolean snapshot) { pw.setAttribute("axis","y"+getYAxis()); //TODO: getTitle is not correct, fix this pw.setAttribute("type",dataSource.getTitle()); pw.openTag("function1d"); String[] pNames = dataSource.getParameterNames(); double[] pValue = dataSource.getParameterValues(); for (int i=0; i<pNames.length; i++) { pw.setAttribute("name",pNames[i]); pw.setAttribute("value",pValue[i]); pw.printTag("functionParam"); } pw.setAttribute("lineColor",jas.util.ColorConverter.colorToString(style.getLineColor())); pw.printTag("functionStyle1d"); pw.closeTag(); } Basic1DFunction getFunction() { return dataSource; } private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.defaultWriteObject(); // things in JASHistData we need to save: out.writeObject(parent); out.writeInt(yAxisIndex); out.writeBoolean(isVisible); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); isVisible = false; // we aren't showing right now parent = (DataManager) in.readObject(); yAxisIndex = in.readInt(); style.addObserver(this); if (in.readBoolean()) { if (dataSource instanceof Observable) ((Observable) dataSource).addObserver(this); show(true); } } public void delete() { ((SupportsFunctions) parent).removeFunction(this); } void destroy() { dataSource.destroy(); dataSource.deleteObserver(this); style.deleteObserver(this); super.deleteNormalizationObserver(); } private Basic1DFunction dataSource; private double xLow; private double xHigh; private double xIncrement; transient private Double hole; private JASHist1DFunctionStyle style; static final long serialVersionUID = -3529869583896718619L; } class JASHistFunctionOverlay extends OverlayWithHandles implements MutableLegendEntry { private static final float[][] lineStyles = {null, { 1, 5 },{ 4, 6 },{ 6, 4, 2, 4 }}; JASHistFunctionOverlay(JASHist1DFunctionData source, JASHist1DFunctionStyle style) { super(source.getDataSource()); this.source = source; this.style = style; } void setXRange(double xmin, double xmax) { this.xmin = xmin; this.xmax = xmax; } public void paint(PlotGraphics g, boolean isPrinting) { final CoordinateTransformation xp = container.getXTransformation(); final CoordinateTransformation yp = container.getYTransformation(source.getYAxis()); Basic1DFunction f = (Basic1DFunction) source.getDataSource(); Transformation xT = null, yT = null; if ( xp instanceof DoubleCoordinateTransformation ) xT = (Transformation) xp; if ( xp instanceof DateCoordinateTransformation ) xT = new DateTransformationConverter((DateCoordinateTransformation) xp); if ( yp instanceof DoubleCoordinateTransformation ) yT = (Transformation) yp; if ( yp instanceof DateCoordinateTransformation ) yT = new DateTransformationConverter((DateCoordinateTransformation) yp); if ( xT != null && yT != null ) { g.setTransformation(xT,yT); double xi = (xmax - xmin) / (xT.convert(xmax) - xT.convert(xmin)); double yold = Double.NEGATIVE_INFINITY; g.setColor(style.getLineColor()); BasicStroke s = new BasicStroke(style.getLineWidth(),BasicStroke.CAP_SQUARE,BasicStroke.JOIN_ROUND,10,lineStyles[style.getLineStyle()],0); g.setStroke(s); int lpbn = 0; for (double x=xmin; x<xmax; x += xi) lpbn++; double[] lpbx = new double[lpbn]; double[] lpby = new double[lpbn]; int count = 0; for (double x=xmin; x<xmax; x += xi) { try { lpbx[count] = x; double y = f.valueAt(x); lpby[count] = y; yold = y; } catch (FunctionValueUndefined xx) { lpby[count] = yold; } count++; } g.drawPolyLine(lpbx, lpby, lpbn); g.setStroke(null); super.paint(g); } } public boolean titleIsChanged() { return source.isLegendChanged(); } public void setTitle(String newTitle) { source.setLegendText(newTitle); } public String getTitle() { return source.getLegendText(); } public void paintIcon(PlotGraphics g, int width, int height) { g.setColor(style.getLineColor()); float flw = (float) style.getLineWidth()*3.0f; if (flw > (width/2)) flw = (width > 2) ? (float) (width/2 -1) : 1; BasicStroke s = new BasicStroke(flw,BasicStroke.CAP_SQUARE,BasicStroke.JOIN_ROUND,10,lineStyles[style.getLineStyle()],0); g.setStroke(s); g.setStroke(s); g.drawLine(1, height/2, width-2, height/2); g.setStroke(null); } private JASHist1DFunctionStyle style; private JASHist1DFunctionData source; private double xmin, xmax; }