From: hama Date: Tue, 12 Jul 2016 21:54:52 +0000 (+0200) Subject: MultiChannelSheet works X-Git-Tag: v0.1~11 X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=533ec7f836f230c7e6f5c3717064a5912b905b75;p=jpinet MultiChannelSheet works --- diff --git a/src/main/java/de/republib/gui/Channel.java b/src/main/java/de/republib/gui/Channel.java new file mode 100644 index 0000000..0e1f9c8 --- /dev/null +++ b/src/main/java/de/republib/gui/Channel.java @@ -0,0 +1,286 @@ +/** + * + */ +package de.republib.gui; + +import java.awt.Color; +import java.awt.Graphics; +import java.util.LinkedList; +import java.util.List; + +import de.republib.util.DoublePair; +import de.republib.util.IPairData; +import de.republib.util.PairData; + +/** + * Manages a set of curves as part of a MultiChannelSheet. + * + * A channel is an area in a diagram with its own real world coordinates. The + * channels are ordered vertically in the sheet. + * + * @author hm + * + */ +public class Channel { + private static final Color colorLegend = Color.BLACK; + private final int index; + private final MultiChannelSheet parent; + private double realX0 = 0.0; + private double realWidth = 1.0; + private double realY0 = 0.0; + private double realHeight = 1.0; + private int x0 = 0; + private int width = 800; + private int y0 = 0; + private int height = 600; + private final List curves = new LinkedList(); + + private final Color[] colorData = { Color.BLUE, Color.RED, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.DARK_GRAY, + Color.ORANGE, Color.PINK }; + + /** + * Constructor. + * + * @param index + * the index in the list of the parent + * @param parent + * the multi channel sheet + */ + public Channel(int index, MultiChannelSheet parent) { + this.index = index; + this.parent = parent; + } + + /** + * @return the data + */ + public List getCurves() { + return this.curves; + } + + /** + * @return the height + */ + public int getHeight() { + return this.height; + } + + /** + * @return the index + */ + public int getIndex() { + return this.index; + } + + /** + * @return the parent + */ + public MultiChannelSheet getParent() { + return this.parent; + } + + /** + * @return the realHeight + */ + public double getRealHeight() { + return this.realHeight; + } + + /** + * @return the realWidth + */ + public double getRealWidth() { + return this.realWidth; + } + + /** + * @return the realX0 + */ + public double getRealX0() { + return this.realX0; + } + + /** + * @return the realY0 + */ + public double getRealY0() { + return this.realY0; + } + + /** + * @return the width + */ + public int getWidth() { + return this.width; + } + + /** + * @return the x0 + */ + public int getX0() { + return this.x0; + } + + /** + * @return the y0 + */ + public int getY0() { + return this.y0; + } + + /** + * Draw the channel. + * + * @param graphics + * the graphical properties + */ + public void paint(Graphics graphics) { + int no = -1; + for (final IPairData curve : this.curves) { + graphics.setColor(this.colorData[++no % this.colorData.length]); + final DoublePair minMax = PairData.minMaxY(curve, null); + this.realX0 = curve.getX(0); + this.realWidth = curve.getX(curve.getSteps() - 1) - this.realX0; + this.realY0 = minMax.getValue1(); + final int steps = curve.getSteps(); + final double maxY = minMax.getValue2(); + this.realHeight = maxY + (maxY - this.realY0) / steps; + int lastX = 0, lastY = 0; + for (int ix = 0; ix < curve.getSteps(); ix++) { + final int x = transformX(curve.getX(ix)); + final int y = transformY(curve.getY(ix)); + if (ix > 0) { + graphics.drawLine(lastX, lastY, x, y); + } + lastX = x; + lastY = y; + } + } + paintLegend(graphics); + } + + /** + * Paints the scale data, title... + * + * @param graphics + * the graphical properties + */ + private void paintLegend(Graphics graphics) { + graphics.setFont(this.parent.getFont()); + graphics.setColor(Channel.colorLegend); + final int x = this.x0 + this.width / 2; + final int y = this.y0 + this.parent.getFontSizeLegend() + 5; + final IPairData data = this.curves.get(0); + graphics.drawString(data.getName(), x, y); + String text = String.format("(%.1g, %.1g)", data.getX(0), data.getY(0)); + graphics.drawString(text, this.x0 + 5, this.y0 + this.getHeight() - this.parent.getFontSizeLegend()); + final int lastIx = data.getSteps() - 1; + text = String.format("(%.1g, %.1g)", data.getX(lastIx), data.getY(lastIx)); + final int width = graphics.getFontMetrics().stringWidth(text); + graphics.drawString(text, this.x0 + this.width - width - 5, y); + } + + /** + * @param height + * the height to set + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @param realHeight + * the realHeight to set + */ + public void setRealHeight(double realHeight) { + this.realHeight = realHeight; + } + + /** + * @param realWidth + * the realWidth to set + */ + public void setRealWidth(double realWidth) { + this.realWidth = realWidth; + } + + /** + * @param realX0 + * the realX0 to set + */ + public void setRealX0(double realX0) { + this.realX0 = realX0; + } + + /** + * @param realY0 + * the realY0 to set + */ + public void setRealY0(double realY0) { + this.realY0 = realY0; + } + + /** + * @param width + * the width to set + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * @param x0 + * the x0 to set + */ + public void setX0(int x0) { + this.x0 = x0; + } + + /** + * @param y0 + * the y0 to set + */ + public void setY0(int y0) { + this.y0 = y0; + } + + /** + * Calculates the x position in pixel from a real x coordinate. + * + * @param x + * the x coordinate in the real world + * @return the x value in pixel coordinate + */ + public int transformX(double x) { + final double xPixel = (x - this.realX0) * (getWidth()) / (this.realWidth); + int rc; + if (xPixel < 0) { + rc = 0; + } else if (xPixel > getWidth()) { + rc = getWidth(); + } else { + rc = (int) Math.round(xPixel); + } + return this.x0 + rc; + } + + /** + * Calculates the y position in pixel from a real y coordinate. + * + * @param y + * the y coordinate in the real world + * @return the y value in pixel coordinate + */ + public int transformY(double y) { + final double yPixel = (y - this.realY0) * (getHeight()) / this.realHeight; + int rc; + if (yPixel < 0) { + rc = getHeight(); + } else if (yPixel > getHeight()) { + rc = -1; + } else { + rc = getHeight() - (int) Math.round(yPixel); + } + return this.y0 + rc; + } +} diff --git a/src/main/java/de/republib/gui/CurveSheet.java b/src/main/java/de/republib/gui/CurveSheet.java new file mode 100644 index 0000000..8b07c95 --- /dev/null +++ b/src/main/java/de/republib/gui/CurveSheet.java @@ -0,0 +1,226 @@ +/** + * + */ +package de.republib.gui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JPanel; + +import de.republib.util.DoublePair; +import de.republib.util.IPairData; +import de.republib.util.PairData; + +/** + * A diagram sheet. + * + *
+ * ----------------------------
+ * |<-- vertic. scale
+ * |
+ * |
+ * |
+ * |          v-- horiz. scale
+ * |__________________________
+ * -----------------------------
+ * 
+ * + * @author hm + * + */ +public class CurveSheet extends JPanel { + /** + * + */ + private static final long serialVersionUID = 1L; + private double realX0 = 0.0; + private double realY0 = 0.0; + private double realWidth = 1.0; + private double realHeight = 1.0; + /// distance horizontal scale to left border + private final int hScaleDistance = 5; + /// distance vertical scale to bottom + private final int vScaleDistance = 5; + private final int widthLine = 3; + private final Color colorScale = Color.DARK_GRAY; + // private final Color colorSheet = Color.WHITE; + private final int fontSizeLegend = 16; + private final List data = new LinkedList(); + private final Color[] colorData = { Color.BLUE, Color.RED, Color.CYAN, Color.GREEN, Color.MAGENTA, Color.DARK_GRAY, + Color.ORANGE, Color.PINK }; + private Font font = null; + + /** + * Appends a data package for drawing one line. + * + * @param data + * the pair data for one line + * @return the instance (for chaining) + */ + public CurveSheet addData(IPairData data) { + this.data.add(data); + return this; + } + + /* + * (non-Javadoc) + * + * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) + */ + @Override + protected void paintComponent(Graphics graphics) { + super.paintComponent(graphics); + paintScale(graphics); + paintData(graphics); + paintLegend(graphics); + } + + /** + * Paints the data as lines in the sheet. + * + * @param graphics + * the graphic environment + */ + protected void paintData(Graphics graphics) { + final double x0 = this.realX0; + final double realWidth = this.realWidth; + final double y0 = this.realY0; + final double realHeight = this.realHeight; + if (this.font == null) { + this.font = new Font(graphics.getFont().getName(), graphics.getFont().getStyle(), this.fontSizeLegend); + + } + final Graphics2D graphics2 = (Graphics2D) graphics; + graphics2.setStroke(new BasicStroke(this.widthLine)); + int no = -1; + for (final IPairData data : this.data) { + graphics.setColor(this.colorData[++no % this.colorData.length]); + final DoublePair minMax = PairData.minMaxY(data, null); + this.realX0 = data.getX(0); + this.realWidth = data.getX(data.getSteps() - 1) - this.realX0; + this.realY0 = minMax.getValue1(); + final int steps = data.getSteps(); + final double maxY = minMax.getValue2(); + this.realHeight = maxY + (maxY - this.realY0) / steps; + int lastX = 0, lastY = 0; + for (int ix = 0; ix < data.getSteps(); ix++) { + final int x = transformX(data.getX(ix)); + final int y = transformY(data.getY(ix)); + if (ix > 0) { + graphics.drawLine(lastX, lastY, x, y); + } + lastX = x; + lastY = y; + } + } + this.realX0 = x0; + this.realWidth = realWidth; + this.realY0 = y0; + this.realHeight = realHeight; + } + + /** + * Paints the data as lines in the sheet. + * + * @param graphics + * the graphic environment + */ + protected void paintLegend(Graphics graphics) { + int no = 1; + final int x = getWidth() / 2; + graphics.setFont(this.font); + for (final IPairData data : this.data) { + final int y = (no + no / 4) * this.fontSizeLegend; + graphics.setColor(this.colorData[(no - 1) % this.colorData.length]); + graphics.drawString(data.getName(), x, y); + graphics.drawLine(x - 20, y, x - 5, y); + ++no; + } + } + + /** + * Paints the scales. + * + * @param graphics + * the graphic environment + */ + protected void paintScale(Graphics graphics) { + graphics.setColor(this.colorScale); + final int y0 = this.getHeight() - this.vScaleDistance; + final int y1 = this.vScaleDistance; + final int x0 = this.hScaleDistance; + final int x1 = this.getWidth() - this.hScaleDistance; + // vertical scale: + // graphics.drawLine(x0, y0, x0, y1); + // horizontal scale: + // graphics.drawLine(x0, y0, x1, y0); + int no = 1; + final int x = getWidth() / 2; + graphics.setFont(this.font); + final int textWidth = 75; + for (final IPairData data : this.data) { + final int yBottom = (no + no / 4) * this.fontSizeLegend; + graphics.setColor(this.colorData[(no - 1) % this.colorData.length]); + // bottom left to-top: xMin + String text = String.format("x0: %.1g", data.getX(0)); + graphics.drawString(text, 2, y0 - this.fontSizeLegend / 2); + // bottom left to-right: yMin + text = String.format("y0: %.1g", data.getY(0)); + graphics.drawString(text, textWidth * no, y0 - this.fontSizeLegend / 2); + // top left: to-right: yMax + text = String.format("y1: %.1g", data.getY(data.getSteps() - 1)); + graphics.drawString(text, textWidth * no + textWidth * no / 8, 3 * this.fontSizeLegend / 2); + // top right: to-bottom: xMax + text = String.format("x1: %.1g", data.getX(data.getSteps() - 1)); + graphics.drawString(text, this.getWidth() - textWidth, + no * this.fontSizeLegend + no * this.fontSizeLegend / 8); + ++no; + } + } + + /** + * Calculates the x position in pixel from a real x coordinate. + * + * @param x + * the x coordinate in the real world + * @return the x value in pixel coordinate + */ + public int transformX(double x) { + final double xPixel = (x - this.realX0) * (getWidth() - 2 * this.hScaleDistance) / (this.realWidth); + int rc; + if (xPixel < 0) { + rc = 0; + } else if (xPixel > getWidth()) { + rc = getWidth(); + } else { + rc = (int) Math.round(xPixel); + } + return rc; + } + + /** + * Calculates the y position in pixel from a real y coordinate. + * + * @param y + * the y coordinate in the real world + * @return the y value in pixel coordinate + */ + public int transformY(double y) { + final double yPixel = (y - this.realY0) * (getHeight() - 2 * this.vScaleDistance) / this.realHeight; + int rc; + if (yPixel < 0) { + rc = getHeight(); + } else if (yPixel > getHeight()) { + rc = -1; + } else { + rc = getHeight() - (int) Math.round(yPixel); + } + return rc; + } +} diff --git a/src/main/java/de/republib/gui/Diagram.java b/src/main/java/de/republib/gui/Diagram.java deleted file mode 100644 index f538ea5..0000000 --- a/src/main/java/de/republib/gui/Diagram.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * - */ -package de.republib.gui; - -import java.awt.Color; -import java.awt.Graphics; -import java.util.LinkedList; -import java.util.List; - -import javax.swing.JPanel; - -import de.republib.util.DoublePair; -import de.republib.util.IPairData; -import de.republib.util.PairData; - -/** - * A diagram sheet. - * - *
- * ----------------------------
- * |<-- vertic. scale
- * |
- * |
- * |
- * |          v-- horiz. scale
- * |__________________________
- * -----------------------------
- * 
- * - * @author hm - * - */ -public class Diagram extends JPanel { - private double realX0 = 0.0; - private double realY0 = 0.0; - private double realWidth = 1.0; - private double realHeight = 1.0; - /// 0.0: no fix ration. Otherwise: width / height - private final double ratio = 800.0 / 600.0; - /// distance horizontal scale to left border - private final int hScaleDistance = 5; - /// distance vertical scale to bottom - private final int vScaleDistance = 5; - private final int scaleWidth = 1; - private final Color colorScale = Color.DARK_GRAY; - private final Color colorScaleFont = Color.BLACK; - private final Color colorSheet = Color.WHITE; - private final List data = new LinkedList(); - - /** - * Appends a data package for drawing one line. - * - * @param data - * the pair data for one line - * @return the instance (for chaining) - */ - public Diagram addData(IPairData data) { - this.data.add(data); - return this; - } - - @Override - protected void paintComponent(Graphics graphics) { - super.paintComponent(graphics); - paintScale(graphics); - paintData(graphics); - } - - /** - * Paints the data as lines in the sheet. - * - * @param graphics - * the graphic environment - */ - protected void paintData(Graphics graphics) { - final double x0 = this.realX0; - final double realWidth = this.realWidth; - final double y0 = this.realY0; - final double realHeight = this.realHeight; - for (final IPairData data : this.data) { - final DoublePair minMax = PairData.minMaxY(data, null); - this.realX0 = data.getX(0); - this.realWidth = data.getX(data.getSteps() - 1) - this.realX0; - this.realY0 = minMax.getValue1(); - final int steps = data.getSteps(); - final double maxY = minMax.getValue2(); - this.realHeight = maxY + (maxY - this.realY0) / steps; - int lastX = 0, lastY = 0; - for (int ix = 0; ix < data.getSteps(); ix++) { - final int x = transformX(data.getX(ix)); - final int y = transformY(data.getY(ix)); - if (ix > 0) { - graphics.drawLine(lastX, lastY, x, y); - } - lastX = x; - lastY = y; - } - } - this.realX0 = x0; - this.realWidth = realWidth; - this.realY0 = y0; - this.realHeight = realHeight; - } - - /** - * Paints the scales. - * - * @param graphics - * the graphic environment - */ - protected void paintScale(Graphics graphics) { - graphics.setColor(this.colorScale); - final int y0 = this.getHeight() - this.vScaleDistance; - final int y1 = this.vScaleDistance; - final int x0 = this.hScaleDistance; - final int x1 = this.getWidth() - this.hScaleDistance; - // vertical scale: - graphics.drawLine(x0, y0, x0, y1); - // horizontal scale: - graphics.drawLine(x0, y0, x1, y0); - - } - - /** - * Calculates the x position in pixel from a real x coordinate. - * - * @param x - * the x coordinate in the real world - * @return the x value in pixel coordinate - */ - public int transformX(double x) { - final double xPixel = (x - this.realX0) * (getWidth() - 2 * this.hScaleDistance); - int rc; - if (xPixel < 0) { - rc = 0; - } else if (xPixel > getWidth()) { - rc = getWidth(); - } else { - rc = (int) Math.round(xPixel); - } - return rc; - } - - /** - * Calculates the y position in pixel from a real y coordinate. - * - * @param y - * the y coordinate in the real world - * @return the y value in pixel coordinate - */ - public int transformY(double y) { - final double yPixel = (y - this.realY0) * (getHeight() - 2 * this.vScaleDistance); - int rc; - if (yPixel < 0) { - rc = getHeight(); - } else if (yPixel > getHeight()) { - rc = -1; - } else { - rc = getHeight() - (int) Math.round(yPixel); - } - return rc; - } -} diff --git a/src/main/java/de/republib/gui/MultiChannelSheet.java b/src/main/java/de/republib/gui/MultiChannelSheet.java new file mode 100644 index 0000000..1619e4f --- /dev/null +++ b/src/main/java/de/republib/gui/MultiChannelSheet.java @@ -0,0 +1,229 @@ +/** + * + */ +package de.republib.gui; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; + +import javax.swing.JPanel; + +import de.republib.util.IPairData; + +/** + * Manages a diagram with multiple channels. + * + * A channel is an area in a diagram with its own real world coordinates. The + * channels are ordered in a grid.
+ *
+ * Screen coordinates:
+ * All channels of a column have the same width. Column widths can be different. + * Channel height can be different. + * + *
+ * __________________________
+ * | channel0 : channel3
+ * --------------------------
+ * | channel1 : channel4
+ * --------------------------
+ * | channel2 :
+ * __________________________
+ * 
+ * + * @author hm + * + */ +public class MultiChannelSheet extends JPanel { + /** + * Serialization UnifiedId. + */ + private static final long serialVersionUID = 1L; + + private final int columnCount = 2; + private final int rowCount = 4; + private final ArrayList channels = new ArrayList<>(); + private final int widthGridLine = 1; + private final Color colorGridLine = Color.BLACK; + private Font font = null; + private final int fontSizeLegend = 14; + + /** + * Constructor. + */ + public MultiChannelSheet() { + addComponentListener(new ResizeListener(this)); + } + + /** + * Adds a channel to the sheet. + * + * @param channel + * the channel to add + * @return the instance (for chaining) + */ + public MultiChannelSheet addChannel(IPairData data) { + final Channel channel = new Channel(this.channels.size(), this); + this.channels.add(channel); + channel.getCurves().add(data); + return this; + } + + /** + * Returns the n-th channel. + * + * @param index + * index of the wanted channel. + * @return null: wrong index
+ * otherwise: the index-th channel + */ + Channel getChannel(int index) { + return index >= 0 && index < this.channels.size() ? this.channels.get(index) : null; + } + + /** + * @return the channelCount + */ + public int getChannelCount() { + return this.channels.size(); + } + + /** + * @return the font + */ + @Override + public Font getFont() { + return this.font; + } + + /** + * @return the fontSizeLegend + */ + public int getFontSizeLegend() { + return this.fontSizeLegend; + } + + /** + * Handles a resize event. + */ + public void onResize() { + resizeChannels(); + } + + /* + * (non-Javadoc) + * + * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) + */ + @Override + protected void paintComponent(Graphics graphics) { + if (this.font == null) { + this.font = new Font(graphics.getFont().getName(), graphics.getFont().getStyle(), this.fontSizeLegend); + } + super.paintComponent(graphics); + paintGrid(graphics); + final int count = getChannelCount(); + for (int index = 0; index < count; index++) { + final Channel channel = this.channels.get(index); + channel.paint(graphics); + } + } + + /** + * Paints the grid lines separating the channel areas. + * + * @param graphics + * the graphics properties + */ + protected void paintGrid(Graphics graphics) { + graphics.setColor(this.colorGridLine); + final int x1 = this.getWidth(); + final int y1 = this.getHeight(); + final int height = y1 / this.rowCount; + final int width = x1 / this.columnCount; + // vertical lines: + for (int ix = 1; ix < this.columnCount; ix++) { + final int x = ix * width; + graphics.drawLine(x, 0, x, y1); + } + // horizontal lines: + for (int ix = 1; ix < this.rowCount; ix++) { + final int y = ix * height; + graphics.drawLine(0, y, x1, y); + } + } + + /** + * Divides the current sheet to the current channels. + */ + private void resizeChannels() { + final int count = getChannelCount(); + int lastY = 0; + int lastX = 0; + final int height = getHeight() / this.rowCount; + int width = getWidth() / this.columnCount; + for (int index = 0; index < count; index++) { + final Channel channel = this.channels.get(index); + final int col = index / this.rowCount; + final int row = index % this.rowCount; + channel.setY0(lastY); + channel.setX0(lastX); + channel.setWidth(width - this.widthGridLine); + if (row % this.rowCount == this.rowCount - 1) { + channel.setHeight(getHeight() - lastY); + lastY = 0; + lastX += width; + if (col == this.columnCount - 1) { + width = getWidth() - lastX; + } + } else { + channel.setHeight(height - this.widthGridLine); + lastY += height; + } + } + } + + /** + * @param channelCount + * the channelCount to set + */ + public void setChannelCount(int channelCount) { + boolean changed = false; + while (this.channels.size() > channelCount) { + this.channels.remove(this.channels.size() - 1); + changed = true; + } + while (this.channels.size() < channelCount) { + this.channels.add(new Channel(this.channels.size(), this)); + changed = true; + } + if (changed) { + resizeChannels(); + } + } + + /** + * @param font + * the font to set + */ + @Override + public void setFont(Font font) { + this.font = font; + } +} + +class ResizeListener extends ComponentAdapter { + MultiChannelSheet sheet; + + ResizeListener(MultiChannelSheet sheet) { + this.sheet = sheet; + } + + @Override + public void componentResized(ComponentEvent e) { + this.sheet.onResize(); + } +} diff --git a/src/main/java/de/republib/pinet/gui/ControlCenter.java b/src/main/java/de/republib/pinet/gui/ControlCenter.java index a08d123..61f7692 100644 --- a/src/main/java/de/republib/pinet/gui/ControlCenter.java +++ b/src/main/java/de/republib/pinet/gui/ControlCenter.java @@ -11,7 +11,7 @@ import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.JTextField; -import de.republib.gui.Diagram; +import de.republib.gui.MultiChannelSheet; import de.republib.util.FunctionPairData; import de.republib.util.I18N; import de.republib.util.MathFunction; @@ -25,7 +25,7 @@ public class ControlCenter { private JPanel panelOutput; private JPanel panelLog; private JLabel labelStatusLine; - private Diagram panelData; + private MultiChannelSheet panelData; private JPanel panelHead; private JTextField textFieldServer; private JTextField textFieldPort; @@ -49,15 +49,27 @@ public class ControlCenter { this.panelCenter.add(this.tabbedPane = new JTabbedPane()); this.tabbedPane.addTab(I18N.tr("Output"), this.panelOutput = new JPanel()); - this.tabbedPane.addTab(I18N.tr("Diagram"), this.panelData = new Diagram()); + this.tabbedPane.addTab(I18N.tr("Diagram"), this.panelData = new MultiChannelSheet()); FunctionPairData function = new FunctionPairData(MathFunction.X, 0.0, 10.0, 790); function.setFactor(9.0); function.setOffset(1.0); - this.panelData.addData(function); + this.panelData.addChannel(function); function = new FunctionPairData(MathFunction.SIN, 0.0, 10.0, 790); function.setFactor(4.0); function.setOffset(5.0); - this.panelData.addData(function); + this.panelData.addChannel(function); + function = new FunctionPairData(MathFunction.COS, 0.0, 10.0, 790); + function.setFactor(4.0); + function.setOffset(5.0); + this.panelData.addChannel(function); + function = new FunctionPairData(MathFunction.LOG, 0.01, 10.0, 790); + this.panelData.addChannel(function); + function = new FunctionPairData(MathFunction.EXP, -5.0, 5.0, 790); + this.panelData.addChannel(function); + function = new FunctionPairData(MathFunction.X2, -1, 2, 790); + this.panelData.addChannel(function); + function = new FunctionPairData(MathFunction.TAN, 0.0, 1.0, 790); + this.panelData.addChannel(function); this.tabbedPane.addTab(I18N.tr("Log"), this.panelLog = new JPanel()); } diff --git a/src/main/java/de/republib/util/BytePairData.java b/src/main/java/de/republib/util/BytePairData.java index 06c10e6..9bedf06 100644 --- a/src/main/java/de/republib/util/BytePairData.java +++ b/src/main/java/de/republib/util/BytePairData.java @@ -18,6 +18,8 @@ public class BytePairData extends DynBytes implements IPairData { private final int dataWidth; + private String name; + /** * Constructor. * @@ -30,9 +32,10 @@ public class BytePairData extends DynBytes implements IPairData { public BytePairData(int capacity, int blocksize, double minX, double maxX, int dataWidth) { super(capacity, blocksize); if (dataWidth < 0 || dataWidth > 8) { - BytePairData.logger.error("getY(): illegal data width: {:d}", dataWidth); + BytePairData.logger.error("getY(): illegal data width: %d", dataWidth); dataWidth = 1; } + this.name = String.format("%d bit data", 8 * dataWidth); this.minX = minX; this.maxX = maxX; this.dataWidth = dataWidth; @@ -59,6 +62,14 @@ public class BytePairData extends DynBytes implements IPairData { return this.minX; } + /** + * @return the name + */ + @Override + public String getName() { + return this.name; + } + /* * (non-Javadoc) * @@ -119,4 +130,12 @@ public class BytePairData extends DynBytes implements IPairData { return y; } + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + } diff --git a/src/main/java/de/republib/util/FunctionPairData.java b/src/main/java/de/republib/util/FunctionPairData.java index a4cf5d1..a315373 100644 --- a/src/main/java/de/republib/util/FunctionPairData.java +++ b/src/main/java/de/republib/util/FunctionPairData.java @@ -24,8 +24,11 @@ public class FunctionPairData implements IPairData { private final int steps; + private String name; + public FunctionPairData(MathFunction function, double xMin, double xMax, int steps) { this.function = function; + this.name = this.function.name(); this.xMax = xMax; this.xMin = xMin; this.steps = steps; @@ -52,6 +55,14 @@ public class FunctionPairData implements IPairData { return this.function; } + /** + * @return the name + */ + @Override + public String getName() { + return this.name; + } + /** * @return the offset */ @@ -129,7 +140,8 @@ public class FunctionPairData implements IPairData { default: break; } - return y * this.factor + this.offset; + y = y * this.factor + this.offset; + return y; } /** @@ -148,6 +160,14 @@ public class FunctionPairData implements IPairData { this.factor2 = factor2; } + /** + * @param name + * the name to set + */ + public void setName(String name) { + this.name = name; + } + /** * @param offset * the offset to set diff --git a/src/main/java/de/republib/util/IPairData.java b/src/main/java/de/republib/util/IPairData.java index 257abca..e1971de 100644 --- a/src/main/java/de/republib/util/IPairData.java +++ b/src/main/java/de/republib/util/IPairData.java @@ -11,6 +11,13 @@ package de.republib.util; */ public interface IPairData { + /** + * Gets a name for the legend. + * + * @return a name of the data + */ + String getName(); + /** * Returns the number of (x, y) pairs. * @@ -35,4 +42,12 @@ public interface IPairData { * @return the index-th x value */ double getY(int index); + + /** + * Sets the name for the legend. + * + * @param name + * the name to set + */ + void setName(String name); } diff --git a/src/main/java/de/republib/util/StringUtils.java b/src/main/java/de/republib/util/StringUtils.java new file mode 100644 index 0000000..26b2aa1 --- /dev/null +++ b/src/main/java/de/republib/util/StringUtils.java @@ -0,0 +1,86 @@ +package de.republib.util; + +/** + * Helper class for strings. + * + * @author hm + * + */ +public class StringUtils { + /** + * Formats a double value. + * + * Wanted: a short string as possible. + * + * @param value + * value to format + * @param precision + * number of "valid digits": 0.034 and 1.2E99 have 2 valid + * digits
+ * precision in [1, 3] + * @return the formatted strings + */ + public static String formatFloat(double value, int precision) { + String rc = null; + if (precision <= 0) { + precision = 1; + } + if (value >= 1E6) { + rc = String.format("%.g", precision - 1, value); + } else if (value > 1.0) { + double limit; + int prec = 0; + switch (precision) { + case 1: + limit = 10.0; + prec = 0; + break; + case 2: + limit = 100.0; + prec = 1; + break; + case 3: + limit = 1000.0; + prec = 2; + break; + default: + limit = 1000.0; + break; + } + if (value >= limit) { + rc = String.format("%d", (int) Math.round(value)); + } else { + rc = String.format("%.*g", prec, value); + } + } else if (value >= 1E-5) { + final double limit; + int prec; + switch (precision) { + case 1: + limit = 1E-4; + prec = 5; + break; + case 2: + limit = 1E-3; + prec = 4; + break; + case 3: + limit = 1E-2; + prec = 3; + break; + default: + limit = 1E-2; + prec = 3; + break; + } + if (value < limit) { + + } else { + rc = String.format("%.*f", prec, value); + } + } else { + rc = String.format("%.*g", precision - 1, value); + } + return rc; + } +} diff --git a/src/test/java/de/republib/util/StringUtilsTest.java b/src/test/java/de/republib/util/StringUtilsTest.java new file mode 100644 index 0000000..799e4e5 --- /dev/null +++ b/src/test/java/de/republib/util/StringUtilsTest.java @@ -0,0 +1,34 @@ +package de.republib.util; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class StringUtilsTest { + + private void checkPrec1() { + final double value = 1234567.77; + Assert.assertEquals(StringUtils.formatFloat(value, 3), "123E6"); + Assert.assertEquals(StringUtils.formatFloat(123456.77, 3), "123456"); + Assert.assertEquals(StringUtils.formatFloat(12345.77, 3), "123456"); + Assert.assertEquals(StringUtils.formatFloat(1234.77, 3), "12345"); + Assert.assertEquals(StringUtils.formatFloat(123.77, 3), "123"); + Assert.assertEquals(StringUtils.formatFloat(12.77, 3), "12.7"); + Assert.assertEquals(StringUtils.formatFloat(1.77, 3), "1.77"); + + } + + private void checkPrec2() { + + } + + private void checkPrec3() { + + } + + @Test + public void formatFloat() { + checkPrec1(); + checkPrec2(); + checkPrec3(); + } +}